shithub: freetype+ttf2subf

Download patch

ref: ee95b6f0d487cb31e90170032ab39d120258052e
parent: 2c1e57096f90cd7e5798c06c4dc4700aa913b2e6
author: Werner Lemberg <[email protected]>
date: Fri Sep 10 10:39:00 EDT 2004

Adding OpenType validation module.  The code is based on the
(unfinished) `otlayout' module but has been heavily modified to make
it much more compact.

* src/otvalid/*: New module.

* include/freetype/ftotval.h, src/base/ftotval.c,
include/freetype/internal/services/svotval.h: New files.

* include/freetype/config/ftmodule.h: Add otv_module_class.
* include/freetype/config/ftheader.h (FT_OPENTYPE_VALIDATE_H): New
macro.
* include/freetype/internal/ftserv.h
(FT_SERVICE_OPENTYPE_VALIDATE_H): New macro.
* include/freetype/internal/fttrace.h (otvmodule, otvcommon,
otvbase, otvgdef, otvgpos, otvgsub, otvjstf): New trace components.

* include/freetype/ftchapters.h: Updated.

* src/base/Jamfile (Library), src/base/descrip.mms (OBJS),
src/base/rules.mk (BASE_EXT_SRC): Updated.

* docs/CHANGES: Updated.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2004-09-09  Werner Lemberg  <[email protected]>
+
+	Adding OpenType validation module.  The code is based on the
+	(unfinished) `otlayout' module but has been heavily modified to make
+	it much more compact.
+
+	* src/otvalid/*: New module.
+
+	* include/freetype/ftotval.h, src/base/ftotval.c,
+	include/freetype/internal/services/svotval.h: New files.
+
+	* include/freetype/config/ftmodule.h: Add otv_module_class.
+	* include/freetype/config/ftheader.h (FT_OPENTYPE_VALIDATE_H): New
+	macro.
+	* include/freetype/internal/ftserv.h
+	(FT_SERVICE_OPENTYPE_VALIDATE_H): New macro.
+	* include/freetype/internal/fttrace.h (otvmodule, otvcommon,
+	otvbase, otvgdef, otvgpos, otvgsub, otvjstf): New trace components.
+
+	* include/freetype/ftchapters.h: Updated.
+
+	* src/base/Jamfile (Library), src/base/descrip.mms (OBJS),
+	src/base/rules.mk (BASE_EXT_SRC): Updated.
+
+	* docs/CHANGES: Updated.
+
 2004-09-08  Werner Lemberg  <[email protected]>
 
 	* src/tools/docmaker/sources.py (re_source_block_format2) <column>:
@@ -13,7 +39,7 @@
 
 	* include/freetype/internal/ftobjs.h: Don't include
 	FT_CONFIG_STANDARD_LIBRARY_H.
-	(FT_Validator, FT_VAlidationLevel, FT_ValidatorRec, FT_VALIDATOR,
+	(FT_Validator, FT_ValidationLevel, FT_ValidatorRec, FT_VALIDATOR,
 	ft_validator_init, ft_validator_run, ft_validator_error, FT_INVALID,
 	FT_INVALID_TOO_SHORT, FT_INVALID_OFFSET, FT_INVALID_FORMAT,
 	FT_INVALID_GLYPH_ID, FT_INVALID_DATA): Move to...
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -23,6 +23,11 @@
     - A  new  API `FT_Sfnt_Table_Info'  (in FT_TRUETYPE_TABLES_H)  has
       been added to retrieve name and size information of SFNT tables.
 
+    - A new API `FT_OpenType_Validate' (in FT_OPENTYPE_VALIDATE_H) has
+      been added to validate OpenType tables  (BASE, GDEF, GPOS, GSUB,
+      JSTF).   After validation  it is  no longer  necessary to  check
+      for errors in those tables.
+
 
 LATEST CHANGES BETWEEN 2.1.9 and 2.1.8
 
--- a/include/freetype/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -18,6 +18,7 @@
 #ifndef __FT_HEADER_H__
 #define __FT_HEADER_H__
 
+
   /*@***********************************************************************/
   /*                                                                       */
   /* <Macro>                                                               */
@@ -92,6 +93,7 @@
   /*                                                                       */
   /*************************************************************************/
 
+
   /* configuration files */
 
   /*************************************************************************/
@@ -362,6 +364,7 @@
   /*                                                                       */
 #define FT_BDF_H  <freetype/ftbdf.h>
 
+
   /*************************************************************************/
   /*                                                                       */
   /* @macro:                                                               */
@@ -528,6 +531,20 @@
   /*    in SFNT-based font formats (i.e. TrueType and OpenType).           */
   /*                                                                       */
 #define FT_SFNT_NAMES_H  <freetype/ftsnames.h>
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* @macro:                                                               */
+  /*    FT_OPENTYPE_VALIDATE_H                                             */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    A macro used in #include statements to name the file containing    */
+  /*    the optional FreeType 2 API used to validate OpenType tables       */
+  /*    (BASE, GDEF, GPOS, GSUB, JSTF).                                    */
+  /*                                                                       */
+#define FT_OPENTYPE_VALIDATE_H  <freetype/ftotval.h>
+
 
   /* */
 
--- a/include/freetype/config/ftmodule.h
+++ b/include/freetype/config/ftmodule.h
@@ -16,4 +16,4 @@
 FT_USE_MODULE(t42_driver_class)
 FT_USE_MODULE(pfr_driver_class)
 FT_USE_MODULE(winfnt_driver_class)
-
+FT_USE_MODULE(otv_module_class)
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -2883,7 +2883,7 @@
   /*    Computations                                                       */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    Crunching fixed numbers and vectors                                */
+  /*    Crunching fixed numbers and vectors.                               */
   /*                                                                       */
   /* <Description>                                                         */
   /*    This section contains various functions used to perform            */
--- a/include/freetype/ftbdf.h
+++ b/include/freetype/ftbdf.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    FreeType API for accessing BDF-specific strings (specification).     */
 /*                                                                         */
-/*  Copyright 2002, 2003 by                                                */
+/*  Copyright 2002, 2003, 2004 by                                          */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -38,13 +38,13 @@
   /*    bdf_fonts                                                          */
   /*                                                                       */
   /* <Title>                                                               */
-  /*    BDF Fonts                                                          */
+  /*    BDF Files                                                          */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    BDF-specific APIs                                                  */
+  /*    BDF specific API.                                                  */
   /*                                                                       */
   /* <Description>                                                         */
-  /*    This section contains the declaration of BDF-specific functions.   */
+  /*    This section contains the declaration of BDF specific functions.   */
   /*                                                                       */
   /*************************************************************************/
 
--- a/include/freetype/ftchapters.h
+++ b/include/freetype/ftchapters.h
@@ -1,5 +1,13 @@
 /***************************************************************************/
 /*                                                                         */
+/* This file defines the structure of the FreeType reference.              */
+/* It is used by the python script which generates the HTML files.         */
+/*                                                                         */
+/***************************************************************************/
+
+
+/***************************************************************************/
+/*                                                                         */
 /* <Chapter>                                                               */
 /*    core_api                                                             */
 /*                                                                         */
@@ -31,6 +39,8 @@
 /*    sfnt_names                                                           */
 /*    bdf_fonts                                                            */
 /*    pfr_fonts                                                            */
+/*    winfnt_fonts                                                         */
+/*    ot_validation                                                        */
 /*                                                                         */
 /***************************************************************************/
 
@@ -62,8 +72,11 @@
 /*    list_processing                                                      */
 /*    outline_processing                                                   */
 /*    raster                                                               */
+/*    glyph_stroker                                                        */
 /*    system_interface                                                     */
 /*    module_management                                                    */
+/*    gzip                                                                 */
+/*    lzw                                                                  */
 /*                                                                         */
 /***************************************************************************/
 
--- a/include/freetype/ftgzip.h
+++ b/include/freetype/ftgzip.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    Gzip-compressed stream support.                                      */
 /*                                                                         */
-/*  Copyright 2002, 2003 by                                                */
+/*  Copyright 2002, 2003, 2004 by                                          */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -40,7 +40,7 @@
   /*    GZIP Streams                                                       */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    Using gzip-compressed font files                                   */
+  /*    Using gzip-compressed font files.                                  */
   /*                                                                       */
   /* <Description>                                                         */
   /*    This section contains the declaration of Gzip-specific functions.  */
--- a/include/freetype/ftimage.h
+++ b/include/freetype/ftimage.h
@@ -772,7 +772,7 @@
   /*    raster                                                             */
   /*                                                                       */
   /* <Title>                                                               */
-  /*    Scanline converter                                                 */
+  /*    Scanline Converter                                                 */
   /*                                                                       */
   /* <Abstract>                                                            */
   /*    How vectorial outlines are converted into bitmaps and pixmaps.     */
--- a/include/freetype/ftlzw.h
+++ b/include/freetype/ftlzw.h
@@ -40,7 +40,7 @@
   /*    LZW Streams                                                        */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    Using LZW-compressed font files                                    */
+  /*    Using LZW-compressed font files.                                   */
   /*                                                                       */
   /* <Description>                                                         */
   /*    This section contains the declaration of LZW-specific functions.   */
--- a/include/freetype/ftmac.h
+++ b/include/freetype/ftmac.h
@@ -41,7 +41,7 @@
   /*    mac_specific                                                       */
   /*                                                                       */
   /* <Title>                                                               */
-  /*    Mac-Specific Interface                                             */
+  /*    Mac Specific Interface                                             */
   /*                                                                       */
   /* <Abstract>                                                            */
   /*    Only available on the Macintosh.                                   */
--- /dev/null
+++ b/include/freetype/ftotval.h
@@ -1,0 +1,159 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftotval.h                                                              */
+/*                                                                         */
+/*    FreeType API for validating OpenType tables (specification).         */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __FTOTVAL_H__
+#define __FTOTVAL_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>                                                             */
+  /*    ot_validation                                                      */
+  /*                                                                       */
+  /* <Title>                                                               */
+  /*    OpenType Validation                                                */
+  /*                                                                       */
+  /* <Abstract>                                                            */
+  /*    An API to validate OpenType tables.                                */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This section contains the declaration of functions to validate     */
+  /*    some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF).               */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+ /**********************************************************************
+  *
+  * @enum:
+  *    FT_VALIDATE_XXX
+  *
+  * @description:
+  *    A list of bit-field constants used with @FT_OpenType_Validate to
+  *    indicate which OpenType tables should be validated.
+  *
+  * @values:
+  *    FT_VALIDATE_BASE ::
+  *      Validate BASE table.
+  *
+  *    FT_VALIDATE_GDEF ::
+  *      Validate GDEF table.
+  *
+  *    FT_VALIDATE_GPOS ::
+  *      Validate GPOS table.
+  *
+  *    FT_VALIDATE_GSUB ::
+  *      Validate GSUB table.
+  *
+  *    FT_VALIDATE_JSTF ::
+  *      Validate JSTF table.
+  *
+  *    FT_VALIDATE_OT ::
+  *      Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF).
+  *
+  */
+#define FT_VALIDATE_BASE  0x0100
+#define FT_VALIDATE_GDEF  0x0200
+#define FT_VALIDATE_GPOS  0x0400
+#define FT_VALIDATE_GSUB  0x0800
+#define FT_VALIDATE_JSTF  0x1000
+
+#define FT_VALIDATE_OT  FT_VALIDATE_BASE | \
+                        FT_VALIDATE_GDEF | \
+                        FT_VALIDATE_GPOS | \
+                        FT_VALIDATE_GSUB | \
+                        FT_VALIDATE_JSTF
+
+  /* */
+
+ /**********************************************************************
+  *
+  * @function:
+  *    FT_OpenType_Validate
+  *
+  * @description:
+  *    Validate various OpenType 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_XXX for possible values.
+  *
+  * @output:
+  *    BASE_table ::
+  *       A pointer to the BASE table.
+  *
+  *    GDEF_table ::
+  *       A pointer to the GDEF table.
+  *
+  *    GPOS_table ::
+  *       A pointer to the GPOS table.
+  *
+  *    GSUB_table ::
+  *       A pointer to the GSUB table.
+  *
+  *    JSTF_table ::
+  *       A pointer to the JSTF table.
+  *
+  * @return:
+  *   FreeType error code.  0 means success.
+  *
+  * @note:
+  *   This function only works with OpenType fonts, returning an error
+  *   otherwise.
+  *
+  *   After use, the application should deallocate the five tables with
+  *   `free'.  A NULL value indicates that the table either doesn't exist
+  *   in the font, or the application hasn't asked for validation.
+  */
+  FT_EXPORT( FT_Error )
+  FT_OpenType_Validate( FT_Face    face,
+                        FT_UInt    validation_flags,
+                        FT_Bytes  *BASE_table, 
+                        FT_Bytes  *GDEF_table, 
+                        FT_Bytes  *GPOS_table, 
+                        FT_Bytes  *GSUB_table, 
+                        FT_Bytes  *JSTF_table );
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTOTVAL_H__ */
+
+
+/* END */
--- a/include/freetype/ftpfr.h
+++ b/include/freetype/ftpfr.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    FreeType API for accessing PFR-specific data (specification only).   */
 /*                                                                         */
-/*  Copyright 2002, 2003 by                                                */
+/*  Copyright 2002, 2003, 2004 by                                          */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -41,7 +41,7 @@
   /*    PFR Fonts                                                          */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    PFR/TrueDoc specific APIs                                          */
+  /*    PFR/TrueDoc specific API.                                          */
   /*                                                                       */
   /* <Description>                                                         */
   /*    This section contains the declaration of PFR-specific functions.   */
@@ -166,7 +166,7 @@
 
 FT_END_HEADER
 
-#endif /* __FTBDF_H__ */
+#endif /* __FTPFR_H__ */
 
 
 /* END */
--- a/include/freetype/ftsizes.h
+++ b/include/freetype/ftsizes.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    FreeType size objects management (specification).                    */
 /*                                                                         */
-/*  Copyright 1996-2001, 2003 by                                           */
+/*  Copyright 1996-2001, 2003, 2004 by                                     */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -48,10 +48,10 @@
   /*    sizes_management                                                   */
   /*                                                                       */
   /* <Title>                                                               */
-  /*    Size management                                                    */
+  /*    Size Management                                                    */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    Managing multiple sizes per face                                   */
+  /*    Managing multiple sizes per face.                                  */
   /*                                                                       */
   /* <Description>                                                         */
   /*    When creating a new face object (e.g. with @FT_New_Face), an       */
--- a/include/freetype/ftstroke.h
+++ b/include/freetype/ftstroke.h
@@ -30,7 +30,7 @@
  /************************************************************************
   *
   * <Section>
-  *    glyph stroker
+  *    glyph_stroker
   *
   * <Title>
   *    Glyph Stroker
--- a/include/freetype/ftwinfnt.h
+++ b/include/freetype/ftwinfnt.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    FreeType API for accessing Windows fnt-specific data.                */
 /*                                                                         */
-/*  Copyright 2003 by                                                      */
+/*  Copyright 2003, 2004 by                                                */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -38,10 +38,10 @@
   /*    winfnt_fonts                                                       */
   /*                                                                       */
   /* <Title>                                                               */
-  /*    Window FNT Fonts                                                   */
+  /*    Window FNT Files                                                   */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    Windows FNT specific APIs                                          */
+  /*    Windows FNT specific API.                                          */
   /*                                                                       */
   /* <Description>                                                         */
   /*    This section contains the declaration of Windows FNT specific      */
--- a/include/freetype/internal/ftserv.h
+++ b/include/freetype/internal/ftserv.h
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    The FreeType services (specification only).                          */
 /*                                                                         */
-/*  Copyright 2003 by                                                      */
+/*  Copyright 2003, 2004 by                                                */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -238,17 +238,18 @@
    *  The header files containing the services.
    */
 
-#define FT_SERVICE_MULTIPLE_MASTERS_H  <freetype/internal/services/svmm.h>
-#define FT_SERVICE_POSTSCRIPT_NAME_H   <freetype/internal/services/svpostnm.h>
-#define FT_SERVICE_POSTSCRIPT_CMAPS_H  <freetype/internal/services/svpscmap.h>
-#define FT_SERVICE_POSTSCRIPT_INFO_H   <freetype/internal/services/svpsinfo.h>
-#define FT_SERVICE_GLYPH_DICT_H        <freetype/internal/services/svgldict.h>
-#define FT_SERVICE_BDF_H               <freetype/internal/services/svbdf.h>
-#define FT_SERVICE_XFREE86_NAME_H      <freetype/internal/services/svxf86nm.h>
-#define FT_SERVICE_SFNT_H              <freetype/internal/services/svsfnt.h>
-#define FT_SERVICE_PFR_H               <freetype/internal/services/svpfr.h>
-#define FT_SERVICE_WINFNT_H            <freetype/internal/services/svwinfnt.h>
-#define FT_SERVICE_TT_CMAP_H           <freetype/internal/services/svttcmap.h>
+#define FT_SERVICE_MULTIPLE_MASTERS_H   <freetype/internal/services/svmm.h>
+#define FT_SERVICE_POSTSCRIPT_NAME_H    <freetype/internal/services/svpostnm.h>
+#define FT_SERVICE_POSTSCRIPT_CMAPS_H   <freetype/internal/services/svpscmap.h>
+#define FT_SERVICE_POSTSCRIPT_INFO_H    <freetype/internal/services/svpsinfo.h>
+#define FT_SERVICE_GLYPH_DICT_H         <freetype/internal/services/svgldict.h>
+#define FT_SERVICE_BDF_H                <freetype/internal/services/svbdf.h>
+#define FT_SERVICE_XFREE86_NAME_H       <freetype/internal/services/svxf86nm.h>
+#define FT_SERVICE_SFNT_H               <freetype/internal/services/svsfnt.h>
+#define FT_SERVICE_PFR_H                <freetype/internal/services/svpfr.h>
+#define FT_SERVICE_WINFNT_H             <freetype/internal/services/svwinfnt.h>
+#define FT_SERVICE_TT_CMAP_H            <freetype/internal/services/svttcmap.h>
+#define FT_SERVICE_OPENTYPE_VALIDATE_H  <freetype/internal/services/svotval.h>
 
  /* */
 
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -37,10 +37,10 @@
 FT_TRACE_DEF( mm )        /* MM interface            (ftmm.c)     */
 FT_TRACE_DEF( raccess )   /* resource fork accessor  (ftrfork.c)  */
 
-/* Cache sub-system */
+  /* Cache sub-system */
 FT_TRACE_DEF( cache )     /* cache sub-system        (ftcache.c, etc.) */
 
-/* SFNT driver components */
+  /* SFNT driver components */
 FT_TRACE_DEF( sfobjs )    /* SFNT object handler     (sfobjs.c)   */
 FT_TRACE_DEF( ttcmap )    /* charmap handler         (ttcmap.c)   */
 FT_TRACE_DEF( ttload )    /* basic TrueType tables   (ttload.c)   */
@@ -47,7 +47,7 @@
 FT_TRACE_DEF( ttpost )    /* PS table processing     (ttpost.c)   */
 FT_TRACE_DEF( ttsbit )    /* TrueType sbit handling  (ttsbit.c)   */
 
-/* TrueType driver components */
+  /* TrueType driver components */
 FT_TRACE_DEF( ttdriver )  /* TT font driver          (ttdriver.c) */
 FT_TRACE_DEF( ttgload )   /* TT glyph loader         (ttgload.c)  */
 FT_TRACE_DEF( ttinterp )  /* bytecode interpreter    (ttinterp.c) */
@@ -55,7 +55,7 @@
 FT_TRACE_DEF( ttpload )   /* TT data/program loader  (ttpload.c)  */
 FT_TRACE_DEF( ttgxvar )   /* TrueType GX var handler (ttgxvar.c)  */
 
-/* Type 1 driver components */
+  /* Type 1 driver components */
 FT_TRACE_DEF( t1driver )
 FT_TRACE_DEF( t1gload )
 FT_TRACE_DEF( t1hint )
@@ -63,16 +63,16 @@
 FT_TRACE_DEF( t1objs )
 FT_TRACE_DEF( t1parse )
 
-/* PostScript helper module `psaux' */
+  /* PostScript helper module `psaux' */
 FT_TRACE_DEF( t1decode )
 FT_TRACE_DEF( psobjs )
 
-/* PostScript hinting module `pshinter' */
+  /* PostScript hinting module `pshinter' */
 FT_TRACE_DEF( pshrec )
 FT_TRACE_DEF( pshalgo1 )
 FT_TRACE_DEF( pshalgo2 )
 
-/* Type 2 driver components */
+  /* Type 2 driver components */
 FT_TRACE_DEF( cffdriver )
 FT_TRACE_DEF( cffgload )
 FT_TRACE_DEF( cffload )
@@ -79,10 +79,10 @@
 FT_TRACE_DEF( cffobjs )
 FT_TRACE_DEF( cffparse )
 
-/* Type 42 driver component */
+  /* Type 42 driver component */
 FT_TRACE_DEF( t42 )
 
-/* CID driver components */
+  /* CID driver components */
 FT_TRACE_DEF( cidafm )
 FT_TRACE_DEF( ciddriver )
 FT_TRACE_DEF( cidgload )
@@ -90,19 +90,28 @@
 FT_TRACE_DEF( cidobjs )
 FT_TRACE_DEF( cidparse )
 
-/* Windows fonts component */
+  /* Windows font component */
 FT_TRACE_DEF( winfnt )
 
-/* PCF fonts components */
+  /* PCF font components */
 FT_TRACE_DEF( pcfdriver )
 FT_TRACE_DEF( pcfread )
 
-/* BDF fonts component */
+  /* BDF font components */
 FT_TRACE_DEF( bdfdriver )
 FT_TRACE_DEF( bdflib )
 
-/* PFR fonts component */
+  /* PFR font component */
 FT_TRACE_DEF( pfr )
+
+  /* OpenType validation components */
+FT_TRACE_DEF( otvmodule )
+FT_TRACE_DEF( otvcommon )
+FT_TRACE_DEF( otvbase )
+FT_TRACE_DEF( otvgdef )
+FT_TRACE_DEF( otvgpos )
+FT_TRACE_DEF( otvgsub )
+FT_TRACE_DEF( otvjstf )
 
 
 /* END */
--- a/include/freetype/internal/ftvalid.h
+++ b/include/freetype/internal/ftvalid.h
@@ -49,7 +49,7 @@
   /* FT_VALIDATE_DEFAULT ::                                                */
   /*   A table that passes this validation level can be used reliably by   */
   /*   FreeType.  It generally means that all offsets have been checked to */
-  /*   prevent out-of-bound reads, array counts are correct, etc.          */
+  /*   prevent out-of-bound reads, that array counts are correct, etc.     */
   /*                                                                       */
   /* FT_VALIDATE_TIGHT ::                                                  */
   /*   A table that passes this validation level can be used reliably and  */
@@ -58,7 +58,7 @@
   /*   be used with FreeType in default mode (the library will simply      */
   /*   return an error later when trying to load the glyph).               */
   /*                                                                       */
-  /*   It also check that fields that must be a multiple of 2, 4, or 8     */
+  /*   It also checks that fields which must be a multiple of 2, 4, or 8,  */
   /*   don't have incorrect values, etc.                                   */
   /*                                                                       */
   /* FT_VALIDATE_PARANOID ::                                               */
--- /dev/null
+++ b/include/freetype/internal/services/svotval.h
@@ -1,0 +1,53 @@
+/***************************************************************************/
+/*                                                                         */
+/*  svotval.h                                                              */
+/*                                                                         */
+/*    The FreeType OpenType validation service (specification).            */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __SVOTVAL_H__
+#define __SVOTVAL_H__
+
+
+FT_BEGIN_HEADER
+
+
+#define FT_SERVICE_ID_OPENTYPE_VALIDATE  "opentype-validate"
+
+
+  typedef FT_Error
+  (*otv_validate_func)( FT_Face    face,
+                        FT_UInt    ot_flags,
+                        FT_Bytes  *base,
+                        FT_Bytes  *gdef,
+                        FT_Bytes  *gpos,
+                        FT_Bytes  *gsub,
+                        FT_Bytes  *jstf );
+
+
+  FT_DEFINE_SERVICE( OTvalidate )
+  {
+    otv_validate_func  validate;
+  };
+
+  /* */
+
+
+FT_END_HEADER
+
+
+#endif /* __SVOTVAL_H__ */
+
+
+/* END */
--- a/include/freetype/tttables.h
+++ b/include/freetype/tttables.h
@@ -42,7 +42,7 @@
   /*    TrueType Tables                                                    */
   /*                                                                       */
   /* <Abstract>                                                            */
-  /*    TrueType-specific table types and functions.                       */
+  /*    TrueType specific table types and functions.                       */
   /*                                                                       */
   /* <Description>                                                         */
   /*    This section contains the definition of TrueType-specific tables   */
--- a/src/base/Jamfile
+++ b/src/base/Jamfile
@@ -24,7 +24,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 ;
+                      ftstroke.c   ftwinfnt.c  ftotval.c ;
 
 # Add Macintosh-specific file to the library when necessary.
 #
--- a/src/base/descrip.mms
+++ b/src/base/descrip.mms
@@ -15,7 +15,7 @@
 
 CFLAGS=$(COMP_FLAGS)$(DEBUG)/include=([--.builds.vms],[--.include],[--.src.base])
 
-OBJS=ftbase.obj,ftinit.obj,ftglyph.obj,ftdebug.obj,ftbdf.obj,ftmm.obj,fttype1.obj,ftxf86.obj,ftpfr.obj,ftstroke.obj,ftwinfnt.obj,ftbbox.obj
+OBJS=ftbase.obj,ftinit.obj,ftglyph.obj,ftdebug.obj,ftbdf.obj,ftmm.obj,fttype1.obj,ftxf86.obj,ftpfr.obj,ftstroke.obj,ftwinfnt.obj,ftbbox.obj,ftotval.obj
 
 all : $(OBJS)
         library [--.lib]freetype.olb $(OBJS)
--- /dev/null
+++ b/src/base/ftotval.c
@@ -1,0 +1,72 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftotval.c                                                              */
+/*                                                                         */
+/*    FreeType API for validating OpenType tables (body).                  */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_OPENTYPE_VALIDATE_H
+
+
+  /* documentation is in ftotval.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_OpenType_Validate( FT_Face    face,
+                        FT_UInt    validation_flags,
+                        FT_Bytes  *BASE_table,
+                        FT_Bytes  *GDEF_table,
+                        FT_Bytes  *GPOS_table,
+                        FT_Bytes  *GSUB_table,
+                        FT_Bytes  *JSTF_table )
+  {
+    FT_Service_OTvalidate  service;
+    FT_Error               error;
+
+
+    if ( !face )
+    {
+      error = FT_Err_Invalid_Face_Handle;
+      goto Exit;
+    }
+
+    if ( !( BASE_table &&
+            GDEF_table &&
+            GPOS_table &&
+            GSUB_table &&
+            JSTF_table ) )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE );
+
+    if ( service )
+      error = service->validate( face,
+                                 validation_flags,
+                                 BASE_table,
+                                 GDEF_table,
+                                 GPOS_table,
+                                 GSUB_table,
+                                 JSTF_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)/ftbdf.c    \
                 $(BASE_DIR)/ftglyph.c  \
                 $(BASE_DIR)/ftmm.c     \
+                $(BASE_DIR)/ftotval.c  \
                 $(BASE_DIR)/ftpfr.c    \
                 $(BASE_DIR)/ftstroke.c \
                 $(BASE_DIR)/fttype1.c  \
--- /dev/null
+++ b/src/otvalid/Jamfile
@@ -1,0 +1,21 @@
+# FreeType 2 src/otvalid Jamfile (c) 2004 Werner Lemberg
+#
+
+SubDir  FT2_TOP $(FT2_SRC_DIR) otvalid ;
+
+{
+  local  _sources ;
+
+  if $(FT2_MULTI)
+  {
+    _sources = otvbase otvcommn otvgdef otvgpos otvgsub otvjstf otvmod ;
+  }
+  else
+  {
+    _sources = otvalid ;
+  }
+
+  Library  $(FT2_LIB) : $(_sources).c ;
+}
+
+# end of src/otvalid Jamfile
--- /dev/null
+++ b/src/otvalid/descrip.mms
@@ -1,0 +1,23 @@
+#
+# FreeType 2 OpenType validation module compilation rules for VMS
+#
+
+
+# Copyright 2004 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+CFLAGS=$(COMP_FLAGS)$(DEBUG)/include=([--.include],[--.src.otvalid])
+
+OBJS=otvalid.obj
+
+all : $(OBJS)
+        library [--.lib]freetype.olb $(OBJS)
+
+# EOF
--- /dev/null
+++ b/src/otvalid/module.mk
@@ -1,0 +1,22 @@
+#
+# FreeType 2 otvalid module definition
+#
+
+
+# Copyright 2004 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+make_module_list: add_otvalid_module
+
+add_otvalid_module:
+	$(OPEN_DRIVER)otvalid_module_class$(CLOSE_DRIVER)
+	$(ECHO_DRIVER)otvalid     $(ECHO_DRIVER_DESC)OpenType validation module$(ECHO_DRIVER_DONE)
+
+# EOF
--- /dev/null
+++ b/src/otvalid/otvalid.c
@@ -1,0 +1,30 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvalid.c                                                              */
+/*                                                                         */
+/*    FreeType validator for OpenType tables (body only).                  */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+
+#include "otvbase.c"
+#include "otvcommn.c"
+#include "otvgdef.c"
+#include "otvgpos.c"
+#include "otvgsub.c"
+#include "otvjstf.c"
+#include "otvmod.c"
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvalid.h
@@ -1,0 +1,72 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvalid.h                                                              */
+/*                                                                         */
+/*    OpenType table validation (specification only).                      */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __OTVALID_H__
+#define __OTVALID_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "otverror.h"           /* must come before FT_INTERNAL_VALIDATE_H */
+
+#include FT_INTERNAL_VALIDATE_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( void )
+  otv_BASE_validate( FT_Bytes      table,
+                     FT_Validator  valid );
+
+  /* GSUB and GPOS tables should already be validated; */
+  /* if missing, set corresponding argument to 0       */
+  FT_LOCAL( void )
+  otv_GDEF_validate( FT_Bytes      table,
+                     FT_Bytes      gsub,
+                     FT_Bytes      gpos,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  otv_GPOS_validate( FT_Bytes      table,
+                     FT_UInt       glyph_count,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  otv_GSUB_validate( FT_Bytes      table,
+                     FT_UInt       glyph_count,
+                     FT_Validator  valid );
+
+  /* GSUB and GPOS tables should already be validated; */
+  /* if missing, set corresponding argument to 0       */
+  FT_LOCAL( void )
+  otv_JSTF_validate( FT_Bytes      table,
+                     FT_Bytes      gsub,
+                     FT_Bytes      gpos,
+                     FT_UInt       glyph_count,
+                     FT_Validator  valid );
+
+
+FT_END_HEADER
+
+#endif /* __OTVALID_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvbase.c
@@ -1,0 +1,318 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvbase.c                                                              */
+/*                                                                         */
+/*    OpenType BASE table validation (body).                               */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "otvalid.h"
+#include "otvcommn.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_otvbase
+
+
+  static void
+  otv_BaseCoord_validate( FT_Bytes       table,
+                          OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   BaseCoordFormat;
+
+
+    OTV_NAME_ENTER( "BaseCoord" );
+
+    OTV_LIMIT_CHECK( 4 );
+    BaseCoordFormat = FT_NEXT_USHORT( p );
+    p += 2;     /* skip Coordinate */
+
+    OTV_TRACE(( " (format %d)\n", BaseCoordFormat ));
+
+    switch ( BaseCoordFormat )
+    {
+    case 1:     /* BaseCoordFormat1 */
+      break;
+
+    case 2:     /* BaseCoordFormat2 */
+      OTV_LIMIT_CHECK( 4 );   /* ReferenceGlyph, BaseCoordPoint */
+      break;
+
+    case 3:     /* BaseCoordFormat3 */
+      OTV_LIMIT_CHECK( 2 );
+      /* DeviceTable */
+      otv_Device_validate( table + FT_NEXT_USHORT( p ), valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  static void
+  otv_BaseTagList_validate( FT_Bytes       table,
+                            OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   BaseTagCount;
+
+
+    OTV_NAME_ENTER( "BaseTagList" );
+
+    OTV_LIMIT_CHECK( 2 );
+
+    BaseTagCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (BaseTagCount = %d)\n", BaseTagCount ));
+
+    OTV_LIMIT_CHECK( BaseTagCount * 4 );          /* BaselineTag */
+
+    OTV_EXIT;
+  }
+
+
+  static void
+  otv_BaseValues_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   BaseCoordCount;
+
+
+    OTV_NAME_ENTER( "BaseValues" );
+
+    OTV_LIMIT_CHECK( 4 );
+
+    p             += 2;                     /* skip DefaultIndex */
+    BaseCoordCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (BaseCoordCount = %d)\n", BaseCoordCount ));
+
+    OTV_LIMIT_CHECK( BaseCoordCount * 2 );
+
+    /* BaseCoord */
+    for ( ; BaseCoordCount > 0; BaseCoordCount-- )
+      otv_BaseCoord_validate( table + FT_NEXT_USHORT( p ), valid );
+
+    OTV_EXIT;
+  }
+
+
+  static void
+  otv_MinMax_validate( FT_Bytes       table,
+                       OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   table_size;
+    FT_UInt   FeatMinMaxCount;
+
+    OTV_OPTIONAL_TABLE( MinCoord );
+    OTV_OPTIONAL_TABLE( MaxCoord );
+
+
+    OTV_NAME_ENTER( "MinMax" );
+
+    OTV_LIMIT_CHECK( 6 );
+
+    OTV_OPTIONAL_OFFSET( MinCoord );
+    OTV_OPTIONAL_OFFSET( MaxCoord );
+    FeatMinMaxCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (FeatMinMaxCount = %d)\n", FeatMinMaxCount ));
+
+    table_size = FeatMinMaxCount * 8 + 6;
+
+    OTV_SIZE_CHECK( MinCoord );
+    if ( MinCoord )
+      otv_BaseCoord_validate( table + MinCoord, valid );
+
+    OTV_SIZE_CHECK( MaxCoord );
+    if ( MaxCoord )
+      otv_BaseCoord_validate( table + MaxCoord, valid );
+
+    OTV_LIMIT_CHECK( FeatMinMaxCount * 8 );
+
+    /* FeatMinMaxRecord */
+    for ( ; FeatMinMaxCount > 0; FeatMinMaxCount-- )
+    {
+      p += 4;                           /* skip FeatureTableTag */
+
+      OTV_OPTIONAL_OFFSET( MinCoord );
+      OTV_OPTIONAL_OFFSET( MaxCoord );
+
+      OTV_SIZE_CHECK( MinCoord );
+      if ( MinCoord )
+        otv_BaseCoord_validate( table + MinCoord, valid );
+
+      OTV_SIZE_CHECK( MaxCoord );
+      if ( MaxCoord )
+        otv_BaseCoord_validate( table + MaxCoord, valid );
+    }
+
+    OTV_EXIT;
+  }
+
+
+  static void
+  otv_BaseScript_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   table_size;
+    FT_UInt   BaseLangSysCount;
+
+    OTV_OPTIONAL_TABLE( BaseValues    );
+    OTV_OPTIONAL_TABLE( DefaultMinMax );
+
+
+    OTV_NAME_ENTER( "BaseScript" );
+
+    OTV_LIMIT_CHECK( 6 );
+    OTV_OPTIONAL_OFFSET( BaseValues    );
+    OTV_OPTIONAL_OFFSET( DefaultMinMax );
+    BaseLangSysCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (BaseLangSysCount = %d)\n", BaseLangSysCount ));
+
+    table_size = BaseLangSysCount * 6 + 6;
+
+    OTV_SIZE_CHECK( BaseValues );
+    if ( BaseValues )
+      otv_BaseValues_validate( table + BaseValues, valid );
+
+    OTV_SIZE_CHECK( DefaultMinMax );
+    if ( DefaultMinMax )
+      otv_MinMax_validate( table + DefaultMinMax, valid );
+
+    OTV_LIMIT_CHECK( BaseLangSysCount * 6 );
+
+    /* BaseLangSysRecord */
+    for ( ; BaseLangSysCount > 0; BaseLangSysCount-- )
+    {
+      p += 4;       /* skip BaseLangSysTag */
+
+      otv_MinMax_validate( table + FT_NEXT_USHORT( p ), valid );
+    }
+
+    OTV_EXIT;
+  }
+
+
+  static void
+  otv_BaseScriptList_validate( FT_Bytes       table,
+                               OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   BaseScriptCount;
+
+
+    OTV_NAME_ENTER( "BaseScriptList" );
+
+    OTV_LIMIT_CHECK( 2 );
+    BaseScriptCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (BaseScriptCount = %d)\n", BaseScriptCount ));
+
+    OTV_LIMIT_CHECK( BaseScriptCount * 6 );
+
+    /* BaseScriptRecord */
+    for ( ; BaseScriptCount > 0; BaseScriptCount-- )
+    {
+      p += 4;       /* skip BaseScriptTag */
+
+      /* BaseScript */
+      otv_BaseScript_validate( table + FT_NEXT_USHORT( p ), valid );
+    }
+
+    OTV_EXIT;
+  }
+
+
+  static void
+  otv_Axis_validate( FT_Bytes       table,
+                     OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   table_size;
+
+    OTV_OPTIONAL_TABLE( BaseTagList );
+
+
+    OTV_NAME_ENTER( "Axis" );
+
+    OTV_LIMIT_CHECK( 4 );
+    OTV_OPTIONAL_OFFSET( BaseTagList );
+
+    table_size = 4;
+
+    OTV_SIZE_CHECK( BaseTagList );
+    if ( BaseTagList )
+      otv_BaseTagList_validate( table + BaseTagList, valid );
+
+    /* BaseScriptList */
+    otv_BaseScriptList_validate( table + FT_NEXT_USHORT( p ), valid );
+
+    OTV_EXIT;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  otv_BASE_validate( FT_Bytes      table,
+                     FT_Validator  ftvalid )
+  {
+    OTV_ValidatorRec  validrec;
+    OTV_Validator     valid = &validrec;
+    FT_Bytes          p     = table;
+    FT_UInt           table_size;
+
+    OTV_OPTIONAL_TABLE( HorizAxis );
+    OTV_OPTIONAL_TABLE( VertAxis  );
+
+
+    valid->root = ftvalid;
+
+    FT_TRACE3(( "validating BASE table\n" ));
+    OTV_INIT;
+
+    OTV_LIMIT_CHECK( 6 );
+
+    if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
+      FT_INVALID_DATA;
+
+    table_size = 6;
+
+    OTV_OPTIONAL_OFFSET( HorizAxis );
+    OTV_SIZE_CHECK( HorizAxis );
+    if ( HorizAxis )
+      otv_Axis_validate( table + HorizAxis, valid );
+
+    OTV_OPTIONAL_OFFSET( VertAxis );
+    OTV_SIZE_CHECK( VertAxis );
+    if ( VertAxis )
+      otv_Axis_validate( table + VertAxis, valid );
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvcommn.c
@@ -1,0 +1,1052 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvcommn.c                                                             */
+/*                                                                         */
+/*    OpenType common tables validation (body).                            */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "otvcommn.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_otvcommon
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       COVERAGE TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  otv_Coverage_validate( FT_Bytes       table,
+                         OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   CoverageFormat;
+
+
+    OTV_NAME_ENTER( "Coverage" );
+
+    OTV_LIMIT_CHECK( 4 );
+    CoverageFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", CoverageFormat ));
+
+    switch ( CoverageFormat )
+    {
+    case 1:     /* CoverageFormat1 */
+      {
+        FT_UInt  GlyphCount;
+
+
+        GlyphCount = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
+
+        OTV_LIMIT_CHECK( GlyphCount * 2 );        /* GlyphArray */
+      }
+      break;
+
+    case 2:     /* CoverageFormat2 */
+      {
+        FT_UInt  n, RangeCount;
+        FT_UInt  Start, End, StartCoverageIndex, total = 0, last = 0;
+
+
+        RangeCount = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (RangeCount = %d)\n", RangeCount ));
+
+        OTV_LIMIT_CHECK( RangeCount * 6 );
+
+        /* RangeRecord */
+        for ( n = 0; n < RangeCount; n++ )
+        {
+          Start              = FT_NEXT_USHORT( p );
+          End                = FT_NEXT_USHORT( p );
+          StartCoverageIndex = FT_NEXT_USHORT( p );
+
+          if ( Start > End || StartCoverageIndex != total )
+            FT_INVALID_DATA;
+
+          if ( n > 0 && Start <= last )
+            FT_INVALID_DATA;
+
+          total += End - Start + 1;
+          last   = End;
+        }
+      }
+      break;
+
+    default:
+      FT_INVALID_FORMAT;
+    }
+
+    /* no need to check glyph indices used as input to coverage tables */
+    /* since even invalid glyph indices return a meaningful result     */
+
+    OTV_EXIT;
+  }
+
+
+  FT_LOCAL_DEF( FT_UInt )
+  otv_Coverage_get_first( FT_Bytes  table )
+  {
+    FT_Bytes  p = table;
+
+
+    p += 4;     /* skip CoverageFormat and Glyph/RangeCount */
+
+    return FT_NEXT_USHORT( p );
+  }
+
+
+  FT_LOCAL_DEF( FT_UInt )
+  otv_Coverage_get_last( FT_Bytes  table )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   CoverageFormat = FT_NEXT_USHORT( p );
+    FT_UInt   count          = FT_NEXT_USHORT( p );     /* Glyph/RangeCount */
+    FT_UInt   result = 0;
+
+
+    switch ( CoverageFormat )
+    {
+    case 1:
+      p += ( count - 1 ) * 2;
+      result = FT_NEXT_USHORT( p );
+      break;
+
+    case 2:
+      p += ( count - 1 ) * 6 + 2;
+      result = FT_NEXT_USHORT( p );
+      break;
+
+    default:
+      ;
+    }
+
+    return result;
+  }
+
+
+  FT_LOCAL_DEF( FT_UInt )
+  otv_Coverage_get_count( FT_Bytes  table )
+  {
+    FT_Bytes  p              = table;
+    FT_UInt   CoverageFormat = FT_NEXT_USHORT( p );
+    FT_UInt   count          = FT_NEXT_USHORT( p );     /* Glyph/RangeCount */
+    FT_UInt   result         = 0;
+
+
+    switch ( CoverageFormat )
+    {
+    case 1:
+      return count;
+
+    case 2:
+      {
+        FT_UInt  Start, End;
+
+
+        for ( ; count > 0; count-- )
+        {
+          Start = FT_NEXT_USHORT( p );
+          End   = FT_NEXT_USHORT( p );
+          p    += 2;                    /* skip StartCoverageIndex */
+
+          result += End - Start + 1;
+        }
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                   CLASS DEFINITION TABLE                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  otv_ClassDef_validate( FT_Bytes       table,
+                         OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   ClassFormat;
+
+
+    OTV_NAME_ENTER( "ClassDef" );
+
+    OTV_LIMIT_CHECK( 4 );
+    ClassFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", ClassFormat ));
+
+    switch ( ClassFormat )
+    {
+    case 1:     /* ClassDefFormat1 */
+      {
+        FT_UInt  GlyphCount;
+
+
+        p += 2;         /* skip StartGlyph */
+
+        OTV_LIMIT_CHECK( 2 );
+
+        OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
+
+        GlyphCount = FT_NEXT_USHORT( p );
+
+        OTV_LIMIT_CHECK( GlyphCount * 2 );    /* ClassValueArray */
+      }
+      break;
+
+    case 2:     /* ClassDefFormat2 */
+      {
+        FT_UInt  n, ClassRangeCount;
+        FT_UInt  Start, End, last = 0;
+
+
+        ClassRangeCount = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount ));
+
+        OTV_LIMIT_CHECK( ClassRangeCount * 6 );
+
+        /* ClassRangeRecord */
+        for ( n = 0; n < ClassRangeCount; n++ )
+        {
+          Start = FT_NEXT_USHORT( p );
+          End   = FT_NEXT_USHORT( p );
+          p    += 2;                        /* skip Class */
+
+          if ( Start > End || ( n > 0 && Start <= last ) )
+            FT_INVALID_DATA;
+
+          last = End;
+        }
+      }
+      break;
+
+    default:
+      FT_INVALID_FORMAT;
+    }
+
+    /* no need to check glyph indices used as input to class definition   */
+    /* tables since even invalid glyph indices return a meaningful result */
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      DEVICE TABLE                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  otv_Device_validate( FT_Bytes       table,
+                       OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   StartSize, EndSize, DeltaFormat, count;
+
+
+    OTV_NAME_ENTER( "Device" );
+
+    OTV_LIMIT_CHECK( 8 );
+    StartSize   = FT_NEXT_USHORT( p );
+    EndSize     = FT_NEXT_USHORT( p );
+    DeltaFormat = FT_NEXT_USHORT( p );
+
+    if ( DeltaFormat < 1 || DeltaFormat > 3 || EndSize < StartSize )
+      FT_INVALID_DATA;
+
+    count = EndSize - StartSize + 1;
+    OTV_LIMIT_CHECK( ( 1 << DeltaFormat ) * count / 8 );  /* DeltaValue */
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         LOOKUPS                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* uses valid->type_count */
+  /* uses valid->type_funcs */
+
+  FT_LOCAL_DEF( void )
+  otv_Lookup_validate( FT_Bytes       table,
+                       OTV_Validator  valid )
+  {
+    FT_Bytes           p = table;
+    FT_UInt            LookupType, SubTableCount;
+    OTV_Validate_Func  validate;
+
+
+    OTV_NAME_ENTER( "Lookup" );
+
+    OTV_LIMIT_CHECK( 6 );
+    LookupType    = FT_NEXT_USHORT( p );
+    p            += 2;                      /* skip LookupFlag */
+    SubTableCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (type %d)\n", LookupType ));
+
+    if ( LookupType == 0 || LookupType >= valid->type_count )
+      FT_INVALID_DATA;
+
+    validate = valid->type_funcs[LookupType - 1];
+
+    OTV_TRACE(( " (SubTableCount = %d)\n", SubTableCount ));
+
+    OTV_LIMIT_CHECK( SubTableCount * 2 );
+
+    /* SubTable */
+    for ( ; SubTableCount > 0; SubTableCount-- )
+      validate( table + FT_NEXT_USHORT( p ), valid );
+
+    OTV_EXIT;
+  }
+
+
+  /* uses valid->lookup_count */
+
+  FT_LOCAL_DEF( void )
+  otv_LookupList_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   LookupCount;
+
+
+    OTV_NAME_ENTER( "LookupList" );
+
+    OTV_LIMIT_CHECK( 2 );
+    LookupCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (LookupCount = %d)\n", LookupCount ));
+
+    OTV_LIMIT_CHECK( LookupCount * 2 );
+
+    valid->lookup_count = LookupCount;
+
+    /* Lookup */
+    for ( ; LookupCount > 0; LookupCount-- )
+      otv_Lookup_validate( table + FT_NEXT_USHORT( p ), valid );
+
+    OTV_EXIT;
+  }
+
+
+  static FT_UInt
+  otv_LookupList_get_count( FT_Bytes  table )
+  {
+    return FT_NEXT_USHORT( table );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        FEATURES                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* uses valid->lookup_count */
+
+  FT_LOCAL_DEF( void )
+  otv_Feature_validate( FT_Bytes       table,
+                        OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   LookupCount;
+
+
+    OTV_NAME_ENTER( "Feature" );
+
+    OTV_LIMIT_CHECK( 4 );
+    p           += 2;                   /* skip FeatureParams (unused) */
+    LookupCount  = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (LookupCount = %d)\n", LookupCount ));
+
+    OTV_LIMIT_CHECK( LookupCount * 2 );
+
+    /* LookupListIndex */
+    for ( ; LookupCount > 0; LookupCount-- )
+      if ( FT_NEXT_USHORT( p ) >= valid->lookup_count )
+        FT_INVALID_DATA;
+
+    OTV_EXIT;
+  }
+
+
+  static FT_UInt
+  otv_Feature_get_count( FT_Bytes  table )
+  {
+    return FT_NEXT_USHORT( table );
+  }
+
+
+  /* sets valid->lookup_count */
+
+  FT_LOCAL_DEF( void )
+  otv_FeatureList_validate( FT_Bytes       table,
+                            FT_Bytes       lookups,
+                            OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   FeatureCount;
+
+
+    OTV_NAME_ENTER( "FeatureList" );
+
+    OTV_LIMIT_CHECK( 2 );
+    FeatureCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount ));
+
+    OTV_LIMIT_CHECK( FeatureCount * 2 );
+
+    valid->lookup_count = otv_LookupList_get_count( lookups );
+
+    /* FeatureRecord */
+    for ( ; FeatureCount > 0; FeatureCount-- )
+    {
+      p += 4;       /* skip FeatureTag */
+
+      /* Feature */
+      otv_Feature_validate( table + FT_NEXT_USHORT( p ), valid );
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       LANGUAGE SYSTEM                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* uses valid->extra1 (number of features) */
+
+  FT_LOCAL_DEF( void )
+  otv_LangSys_validate( FT_Bytes       table,
+                        OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   ReqFeatureIndex;
+    FT_UInt   FeatureCount;
+
+
+    OTV_NAME_ENTER( "LangSys" );
+
+    OTV_LIMIT_CHECK( 6 );
+    p              += 2;                    /* skip LookupOrder (unused) */
+    ReqFeatureIndex = FT_NEXT_USHORT( p );
+    FeatureCount    = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (ReqFeatureIndex = %d)\n", ReqFeatureIndex ));
+    OTV_TRACE(( " (FeatureCount = %d)\n",    FeatureCount    ));
+
+    if ( ReqFeatureIndex != 0xFFFFU && ReqFeatureIndex >= valid->extra1 )
+      FT_INVALID_DATA;
+
+    OTV_LIMIT_CHECK( FeatureCount * 2 );
+
+    /* FeatureIndex */
+    for ( ; FeatureCount > 0; FeatureCount-- )
+      if ( FT_NEXT_USHORT( p ) >= valid->extra1 )
+        FT_INVALID_DATA;
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           SCRIPTS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  otv_Script_validate( FT_Bytes       table,
+                       OTV_Validator  valid )
+  {
+    FT_UInt   DefaultLangSys, LangSysCount;
+    FT_Bytes  p = table;
+
+
+    OTV_NAME_ENTER( "Script" );
+
+    OTV_LIMIT_CHECK( 4 );
+    DefaultLangSys = FT_NEXT_USHORT( p );
+    LangSysCount   = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (LangSysCount = %d)\n", LangSysCount ));
+
+    if ( DefaultLangSys != 0 )
+      otv_LangSys_validate( table + DefaultLangSys, valid );
+
+    OTV_LIMIT_CHECK( LangSysCount * 6 );
+
+    /* LangSysRecord */
+    for ( ; LangSysCount > 0; LangSysCount-- )
+    {
+      p += 4;       /* skip LangSysTag */
+
+      /* LangSys */
+      otv_LangSys_validate( table + FT_NEXT_USHORT( p ), valid );
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /* sets valid->extra1 (number of features) */
+
+  FT_LOCAL_DEF( void )
+  otv_ScriptList_validate( FT_Bytes       table,
+                           FT_Bytes       features,
+                           OTV_Validator  valid )
+  {
+    FT_UInt   ScriptCount;
+    FT_Bytes  p = table;
+
+
+    OTV_NAME_ENTER( "ScriptList" );
+
+    OTV_LIMIT_CHECK( 2 );
+    ScriptCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (ScriptCount = %d)\n", ScriptCount ));
+
+    OTV_LIMIT_CHECK( ScriptCount * 6 );
+
+    valid->extra1 = otv_Feature_get_count( features );
+
+    /* ScriptRecord */
+    for ( ; ScriptCount > 0; ScriptCount-- )
+    {
+      p += 4;       /* skip ScriptTag */
+
+      otv_Script_validate( table + FT_NEXT_USHORT( p ), valid ); /* Script */
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      UTILITY FUNCTIONS                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*
+     u:   uint16
+     ux:  unit16 [x]
+
+     s:   struct
+     sx:  struct [x]
+     sxy: struct [x], using external y count
+
+     x:   uint16 x
+
+     C:   Coverage
+
+     O:   Offset
+     On:  Offset (NULL)
+     Ox:  Offset [x]
+     Onx: Offset (NULL) [x]
+  */
+
+  FT_LOCAL_DEF( void )
+  otv_x_Ox( FT_Bytes       table,
+            OTV_Validator  valid )
+  {
+    FT_Bytes           p = table;
+    FT_UInt            Count;
+    OTV_Validate_Func  func;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 2 );
+    Count = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (Count = %d)\n", Count ));
+
+    OTV_LIMIT_CHECK( Count * 2 );
+
+    valid->nesting_level++;
+    func = valid->func[valid->nesting_level];
+
+    for ( ; Count > 0; Count-- )
+      func( table + FT_NEXT_USHORT( p ), valid );
+
+    valid->nesting_level--;
+
+    OTV_EXIT;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  otv_u_C_x_Ox( FT_Bytes       table,
+                OTV_Validator  valid )
+  {
+    FT_Bytes           p = table;
+    FT_UInt            Count, Coverage;
+    OTV_Validate_Func  func;
+
+
+    OTV_ENTER;
+
+    p += 2;     /* skip Format */
+
+    OTV_LIMIT_CHECK( 4 );
+    Coverage = FT_NEXT_USHORT( p );
+    Count    = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (Count = %d)\n", Count ));
+
+    otv_Coverage_validate( table + Coverage, valid );
+
+    OTV_LIMIT_CHECK( Count * 2 );
+
+    valid->nesting_level++;
+    func = valid->func[valid->nesting_level];
+
+    for ( ; Count > 0; Count-- )
+      func( table + FT_NEXT_USHORT( p ), valid );
+
+    valid->nesting_level--;
+
+    OTV_EXIT;
+  }
+
+
+  /* uses valid->extra1 (if > 0: array value limit) */
+
+  FT_LOCAL_DEF( void )
+  otv_x_ux( FT_Bytes       table,
+            OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   Count;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 2 );
+    Count = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (Count = %d)\n", Count ));
+
+    OTV_LIMIT_CHECK( Count * 2 );
+
+    if ( valid->extra1 )
+    {
+      for ( ; Count > 0; Count-- )
+        if ( FT_NEXT_USHORT( p ) >= valid->extra1 )
+          FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /* `ux' in the function's name is not really correct since only x-1 */
+  /* elements are tested                                              */
+
+  /* uses valid->extra1 (array value limit) */
+
+  FT_LOCAL_DEF( void )
+  otv_x_y_ux_sy( FT_Bytes       table,
+                 OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   Count1, Count2;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 4 );
+    Count1 = FT_NEXT_USHORT( p );
+    Count2 = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (Count1 = %d)\n", Count1 ));
+    OTV_TRACE(( " (Count2 = %d)\n", Count2 ));
+
+    if ( Count1 == 0 )
+      FT_INVALID_DATA;
+
+    OTV_LIMIT_CHECK( ( Count1 - 1 ) * 2 + Count2 * 4 );
+
+    for ( ; Count2 > 0; Count2-- )
+    {
+      if ( FT_NEXT_USHORT( p ) >= Count1 )
+        FT_INVALID_DATA;
+
+      if ( FT_NEXT_USHORT( p ) >= valid->extra1 )
+        FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /* `uy' in the function's name is not really correct since only y-1 */
+  /* elements are tested                                              */
+
+  /* uses valid->extra1 (array value limit) */
+
+  FT_LOCAL_DEF( void )
+  otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   BacktrackCount, InputCount, LookaheadCount;
+    FT_UInt   Count;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 2 );
+    BacktrackCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (BacktrackCount = %d)\n", BacktrackCount ));
+
+    OTV_LIMIT_CHECK( BacktrackCount * 2 + 2 );
+    p += BacktrackCount * 2;
+
+    InputCount = FT_NEXT_USHORT( p );
+    if ( InputCount == 0 )
+      FT_INVALID_DATA;
+
+    OTV_TRACE(( " (InputCount = %d)\n", InputCount ));
+
+    OTV_LIMIT_CHECK( InputCount * 2 );
+    p += ( InputCount - 1 ) * 2;
+
+    LookaheadCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (LookaheadCount = %d)\n", LookaheadCount ));
+
+    OTV_LIMIT_CHECK( LookaheadCount * 2 + 2 );
+    p += LookaheadCount * 2;
+
+    Count = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (Count = %d)\n", Count ));
+
+    OTV_LIMIT_CHECK( Count * 4 );
+
+    for ( ; Count > 0; Count-- )
+    {
+      if ( FT_NEXT_USHORT( p ) >= InputCount )
+        FT_INVALID_DATA;
+
+      if ( FT_NEXT_USHORT( p ) >= valid->extra1 )
+        FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /* sets valid->extra1 (valid->lookup_count) */
+
+  FT_LOCAL_DEF( void )
+  otv_u_O_O_x_Onx( FT_Bytes       table,
+                   OTV_Validator  valid )
+  {
+    FT_Bytes           p = table;
+    FT_UInt            Coverage, ClassDef, ClassSetCount;
+    OTV_Validate_Func  func;
+
+
+    OTV_ENTER;
+
+    p += 2;     /* skip Format */
+
+    OTV_LIMIT_CHECK( 6 );
+    Coverage      = FT_NEXT_USHORT( p );
+    ClassDef      = FT_NEXT_USHORT( p );
+    ClassSetCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (ClassSetCount = %d)\n", ClassSetCount ));
+
+    otv_Coverage_validate( table + Coverage, valid );
+    otv_ClassDef_validate( table + ClassDef, valid );
+
+    OTV_LIMIT_CHECK( ClassSetCount * 2 );
+
+    valid->nesting_level++;
+    func          = valid->func[valid->nesting_level];
+    valid->extra1 = valid->lookup_count;
+
+    for ( ; ClassSetCount > 0; ClassSetCount-- )
+    {
+      FT_UInt  offset = FT_NEXT_USHORT( p );
+
+
+      if ( offset )
+        func( table + offset, valid );
+    }
+
+    valid->nesting_level--;
+
+    OTV_EXIT;
+  }
+
+
+  /* uses valid->lookup_count */
+
+  FT_LOCAL_DEF( void )
+  otv_u_x_y_Ox_sy( FT_Bytes       table,
+                   OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   GlyphCount, Count, count1;
+
+
+    OTV_ENTER;
+
+    p += 2;     /* skip Format */
+
+    OTV_LIMIT_CHECK( 4 );
+    GlyphCount = FT_NEXT_USHORT( p );
+    Count      = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
+    OTV_TRACE(( " (Count = %d)\n",      Count      ));
+
+    OTV_LIMIT_CHECK( GlyphCount * 2 + Count * 4 );
+
+    for ( count1 = GlyphCount; count1 > 0; count1-- )
+      otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid );
+
+    for ( ; Count > 0; Count-- )
+    {
+      if ( FT_NEXT_USHORT( p ) >= GlyphCount )
+        FT_INVALID_DATA;
+
+      if ( FT_NEXT_USHORT( p ) >= valid->lookup_count )
+        FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /* sets valid->extra1 (valid->lookup_count)    */
+
+  FT_LOCAL_DEF( void )
+  otv_u_O_O_O_O_x_Onx( FT_Bytes       table,
+                       OTV_Validator  valid )
+  {
+    FT_Bytes           p = table;
+    FT_UInt            Coverage;
+    FT_UInt            BacktrackClassDef, InputClassDef, LookaheadClassDef;
+    FT_UInt            ChainClassSetCount;
+    OTV_Validate_Func  func;
+
+
+    OTV_ENTER;
+
+    p += 2;     /* skip Format */
+
+    OTV_LIMIT_CHECK( 10 );
+    Coverage           = FT_NEXT_USHORT( p );
+    BacktrackClassDef  = FT_NEXT_USHORT( p );
+    InputClassDef      = FT_NEXT_USHORT( p );
+    LookaheadClassDef  = FT_NEXT_USHORT( p );
+    ChainClassSetCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (ChainClassSetCount = %d)\n", ChainClassSetCount ));
+
+    otv_Coverage_validate( table + Coverage, valid );
+
+    otv_ClassDef_validate( table + BacktrackClassDef,  valid );
+    otv_ClassDef_validate( table + InputClassDef, valid );
+    otv_ClassDef_validate( table + LookaheadClassDef, valid );
+
+    OTV_LIMIT_CHECK( ChainClassSetCount * 2 );
+
+    valid->nesting_level++;
+    func          = valid->func[valid->nesting_level];
+    valid->extra1 = valid->lookup_count;
+
+    for ( ; ChainClassSetCount > 0; ChainClassSetCount-- )
+    {
+      FT_UInt  offset = FT_NEXT_USHORT( p );
+
+
+      if ( offset )
+        func( table + offset, valid );
+    }
+
+    valid->nesting_level--;
+
+    OTV_EXIT;
+  }
+
+
+  /* uses valid->lookup_count */
+
+  FT_LOCAL_DEF( void )
+  otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes       table,
+                             OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   BacktrackGlyphCount, InputGlyphCount, LookaheadGlyphCount;
+    FT_UInt   count1, count2;
+
+
+    OTV_ENTER;
+
+    p += 2;     /* skip Format */
+
+    OTV_LIMIT_CHECK( 2 );
+    BacktrackGlyphCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount ));
+
+    OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 );
+
+    for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- )
+      otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid );
+
+    InputGlyphCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (InputGlyphCount = %d)\n", InputGlyphCount ));
+
+    OTV_LIMIT_CHECK( InputGlyphCount * 2 + 2 );
+
+    for ( count1 = InputGlyphCount; count1 > 0; count1-- )
+      otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid );
+
+    LookaheadGlyphCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount ));
+
+    OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 );
+
+    for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- )
+      otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid );
+
+    count2 = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (Count = %d)\n", count2 ));
+
+    OTV_LIMIT_CHECK( count2 * 4 );
+
+    for ( ; count2 > 0; count2-- )
+    {
+      if ( FT_NEXT_USHORT( p ) >= InputGlyphCount )
+        FT_INVALID_DATA;
+
+      if ( FT_NEXT_USHORT( p ) >= valid->lookup_count )
+        FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  FT_LOCAL_DEF( FT_UInt )
+  otv_GSUBGPOS_get_Lookup_count( FT_Bytes  table )
+  {
+    FT_Bytes  p = table + 8;
+
+
+    return otv_LookupList_get_count( table + FT_NEXT_USHORT( p ) );
+  }
+
+
+  FT_LOCAL_DEF( FT_UInt )
+  otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes  table )
+  {
+    FT_Bytes  p, lookup;
+    FT_UInt   count;
+
+
+    /* LookupList */
+    p      = table + 8;
+    table += FT_NEXT_USHORT( p );
+
+    /* LookupCount */
+    p     = table;
+    count = FT_NEXT_USHORT( p );
+
+    for ( ; count > 0; count-- )
+    {
+      FT_Bytes  oldp;
+
+
+      /* Lookup */
+      lookup = table + FT_NEXT_USHORT( p );
+
+      oldp = p;
+
+      /* LookupFlag */
+      p = lookup + 2;
+      if ( FT_NEXT_USHORT( p ) & 0xFF00U )
+        return 1;
+
+      p = oldp;
+    }
+
+    return 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvcommn.h
@@ -1,0 +1,442 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvcommn.h                                                             */
+/*                                                                         */
+/*    OpenType common tables validation (specification).                   */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __OTVCOMMN_H__
+#define __OTVCOMMN_H__
+
+
+#include <ft2build.h>
+#include "otvalid.h"
+#include FT_INTERNAL_DEBUG_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         VALIDATION                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct OTV_ValidatorRec_*  OTV_Validator;
+
+  typedef void  (*OTV_Validate_Func)( FT_Bytes       table,
+                                      OTV_Validator  valid );
+
+  typedef struct  OTV_ValidatorRec_
+  {
+    FT_Validator        root;
+    FT_UInt             type_count;
+    OTV_Validate_Func*  type_funcs;
+
+    FT_UInt             lookup_count;
+    FT_UInt             glyph_count;
+
+    FT_UInt             nesting_level;
+
+    OTV_Validate_Func   func[3];
+
+    FT_UInt             extra1;     /* for passing parameters */
+    FT_UInt             extra2;
+    FT_Bytes            extra3;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    FT_UInt             debug_indent;
+    const FT_String*    debug_function_name[3];
+#endif
+
+  } OTV_ValidatorRec;
+
+
+#undef  FT_INVALID_
+#define FT_INVALID_( _prefix, _error ) \
+          ft_validator_error( valid->root, _prefix ## _error )
+
+#define OTV_OPTIONAL_TABLE( _table )  FT_UInt   _table;      \
+                                      FT_Bytes  _table ## _p
+
+#define OTV_OPTIONAL_OFFSET( _offset )           \
+          FT_BEGIN_STMNT                         \
+            _offset ## _p = p;                   \
+            _offset       = FT_NEXT_USHORT( p ); \
+          FT_END_STMNT
+
+#define OTV_LIMIT_CHECK( _count )                    \
+          FT_BEGIN_STMNT                             \
+            if ( p + (_count) > valid->root->limit ) \
+              FT_INVALID_TOO_SHORT;                  \
+          FT_END_STMNT
+
+#define OTV_SIZE_CHECK( _size )                                        \
+          FT_BEGIN_STMNT                                               \
+            if ( _size > 0 && _size < table_size )                     \
+            {                                                          \
+              if ( valid->root->level == FT_VALIDATE_PARANOID )        \
+                FT_INVALID_OFFSET;                                     \
+              else                                                     \
+              {                                                        \
+                /* strip off `const' */                                \
+                FT_Byte*  pp = (FT_Byte*)_size ## _p;                  \
+                                                                       \
+                                                                       \
+                FT_TRACE3(( "\n"                                       \
+                            "Invalid offset to optional table `%s'!\n" \
+                            "Set to zero.\n"                           \
+                            "\n", #_size ));                           \
+                                                                       \
+                /* always assume 16bit entities */                     \
+                _size = pp[0] = pp[1] = 0;                             \
+              }                                                        \
+            }                                                          \
+          FT_END_STMNT
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+  /* use preprocessor's argument prescan to expand one argument into two */
+#define OTV_NEST1( x )  OTV_NEST1_( x )
+#define OTV_NEST1_( func0, name0 )                 \
+          FT_BEGIN_STMNT                           \
+            valid->nesting_level          = 0;     \
+            valid->func[0]                = func0; \
+            valid->debug_function_name[0] = name0; \
+          FT_END_STMNT
+
+  /* use preprocessor's argument prescan to expand two arguments into four */
+#define OTV_NEST2( x, y )  OTV_NEST2_( x, y )
+#define OTV_NEST2_( func0, name0, func1, name1 )   \
+          FT_BEGIN_STMNT                           \
+            valid->nesting_level          = 0;     \
+            valid->func[0]                = func0; \
+            valid->func[1]                = func1; \
+            valid->debug_function_name[0] = name0; \
+            valid->debug_function_name[1] = name1; \
+          FT_END_STMNT
+
+  /* use preprocessor's argument prescan to expand three arguments into six */
+#define OTV_NEST3( x, y, z )  OTV_NEST3_( x, y, z )
+#define OTV_NEST3_( func0, name0, func1, name1, func2, name2 ) \
+          FT_BEGIN_STMNT                                       \
+            valid->nesting_level          = 0;                 \
+            valid->func[0]                = func0;             \
+            valid->func[1]                = func1;             \
+            valid->func[2]                = func2;             \
+            valid->debug_function_name[0] = name0;             \
+            valid->debug_function_name[1] = name1;             \
+            valid->debug_function_name[2] = name2;             \
+          FT_END_STMNT
+
+#define OTV_INIT  valid->debug_indent = 0
+
+#define OTV_ENTER                                                            \
+          FT_BEGIN_STMNT                                                     \
+            valid->debug_indent += 2;                                        \
+            FT_TRACE4(( "%*.s", valid->debug_indent, 0 ));                   \
+            FT_TRACE4(( "%s table\n",                                        \
+                        valid->debug_function_name[valid->nesting_level] )); \
+          FT_END_STMNT
+
+#define OTV_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 OTV_EXIT  valid->debug_indent -= 2
+
+#define OTV_TRACE( s )                                     \
+          FT_BEGIN_STMNT                                   \
+            FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \
+            FT_TRACE4( s );                                \
+          FT_END_STMNT
+
+#else   /* !FT_DEBUG_LEVEL_TRACE */
+
+  /* use preprocessor's argument prescan to expand one argument into two */
+#define OTV_NEST1( x )  OTV_NEST1_( x )
+#define OTV_NEST1_( func0, name0 )        \
+          FT_BEGIN_STMNT                  \
+            valid->nesting_level = 0;     \
+            valid->func[0]       = func0; \
+          FT_END_STMNT
+
+  /* use preprocessor's argument prescan to expand two arguments into four */
+#define OTV_NEST2( x, y )  OTV_NEST2_( x, y )
+#define OTV_NEST2_( func0, name0, func1, name1 ) \
+          FT_BEGIN_STMNT                         \
+            valid->nesting_level = 0;            \
+            valid->func[0]       = func0;        \
+            valid->func[1]       = func1;        \
+          FT_END_STMNT
+
+  /* use preprocessor's argument prescan to expand three arguments into six */
+#define OTV_NEST3( x, y, z )  OTV_NEST3_( x, y, z )
+#define OTV_NEST3_( func0, name0, func1, name1, func2, name2 ) \
+          FT_BEGIN_STMNT                                       \
+            valid->nesting_level = 0;                          \
+            valid->func[0]       = func0;                      \
+            valid->func[1]       = func1;                      \
+            valid->func[2]       = func2;                      \
+          FT_END_STMNT
+
+#define OTV_INIT                do ; while ( 0 )
+#define OTV_ENTER               do ; while ( 0 )
+#define OTV_NAME_ENTER( name )  do ; while ( 0 )
+#define OTV_EXIT                do ; while ( 0 )
+
+#define OTV_TRACE( s )          do ; while ( 0 )
+
+#endif  /* !FT_DEBUG_LEVEL_TRACE */
+
+
+#define OTV_RUN  valid->func[0]
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       COVERAGE TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  otv_Coverage_validate( FT_Bytes       table,
+                         OTV_Validator  valid );
+
+  /* return first covered glyph */
+  FT_LOCAL( FT_UInt )
+  otv_Coverage_get_first( FT_Bytes  table );
+
+  /* return last covered glyph */
+  FT_LOCAL( FT_UInt )
+  otv_Coverage_get_last( FT_Bytes  table );
+
+  /* return number of covered glyphs */
+  FT_LOCAL( FT_UInt )
+  otv_Coverage_get_count( FT_Bytes  table );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  CLASS DEFINITION TABLE                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  otv_ClassDef_validate( FT_Bytes       table,
+                         OTV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      DEVICE TABLE                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  otv_Device_validate( FT_Bytes       table,
+                       OTV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           LOOKUPS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  otv_Lookup_validate( FT_Bytes       table,
+                       OTV_Validator  valid );
+
+  FT_LOCAL( void )
+  otv_LookupList_validate( FT_Bytes       table,
+                           OTV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        FEATURES                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  otv_Feature_validate( FT_Bytes       table,
+                        OTV_Validator  valid );
+
+  /* lookups must already be validated */
+  FT_LOCAL( void )
+  otv_FeatureList_validate( FT_Bytes       table,
+                            FT_Bytes       lookups,
+                            OTV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       LANGUAGE SYSTEM                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  otv_LangSys_validate( FT_Bytes       table,
+                        OTV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           SCRIPTS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  otv_Script_validate( FT_Bytes       table,
+                       OTV_Validator  valid );
+
+  /* features must already be validated */
+  FT_LOCAL( void )
+  otv_ScriptList_validate( FT_Bytes       table,
+                           FT_Bytes       features,
+                           OTV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      UTILITY FUNCTIONS                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define ChainPosClassSet  otv_x_Ox, "ChainPosClassSet"
+#define ChainPosRuleSet   otv_x_Ox, "ChainPosRuleSet" 
+#define ChainSubClassSet  otv_x_Ox, "ChainSubClassSet"
+#define ChainSubRuleSet   otv_x_Ox, "ChainSubRuleSet"
+#define JstfLangSys       otv_x_Ox, "JstfLangSys"
+#define JstfMax           otv_x_Ox, "JstfMax" 
+#define LigGlyph          otv_x_Ox, "LigGlyph"
+#define LigatureArray     otv_x_Ox, "LigatureArray"
+#define LigatureSet       otv_x_Ox, "LigatureSet"
+#define PosClassSet       otv_x_Ox, "PosClassSet"
+#define PosRuleSet        otv_x_Ox, "PosRuleSet" 
+#define SubClassSet       otv_x_Ox, "SubClassSet"
+#define SubRuleSet        otv_x_Ox, "SubRuleSet"
+
+  FT_LOCAL( void )
+  otv_x_Ox ( FT_Bytes       table,
+             OTV_Validator  valid );
+
+#define AlternateSubstFormat1     otv_u_C_x_Ox, "AlternateSubstFormat1"        
+#define ChainContextPosFormat1    otv_u_C_x_Ox, "ChainContextPosFormat1"       
+#define ChainContextSubstFormat1  otv_u_C_x_Ox, "ChainContextSubstFormat1"     
+#define ContextPosFormat1         otv_u_C_x_Ox, "ContextPosFormat1"            
+#define ContextSubstFormat1       otv_u_C_x_Ox, "ContextSubstFormat1"          
+#define LigatureSubstFormat1      otv_u_C_x_Ox, "LigatureSubstFormat1"         
+#define MultipleSubstFormat1      otv_u_C_x_Ox, "MultipleSubstFormat1"         
+
+  FT_LOCAL( void )
+  otv_u_C_x_Ox( FT_Bytes       table,
+                OTV_Validator  valid );
+
+#define AlternateSet     otv_x_ux, "AlternateSet"     
+#define AttachPoint      otv_x_ux, "AttachPoint"      
+#define ExtenderGlyph    otv_x_ux, "ExtenderGlyph"    
+#define JstfGPOSModList  otv_x_ux, "JstfGPOSModList"
+#define JstfGSUBModList  otv_x_ux, "JstfGSUBModList"  
+#define Sequence         otv_x_ux, "Sequence"         
+
+  FT_LOCAL( void )
+  otv_x_ux( FT_Bytes       table,
+            OTV_Validator  valid );
+
+#define PosClassRule  otv_x_y_ux_sy, "PosClassRule"
+#define PosRule       otv_x_y_ux_sy, "PosRule"
+#define SubClassRule  otv_x_y_ux_sy, "SubClassRule"
+#define SubRule       otv_x_y_ux_sy, "SubRule"
+
+  FT_LOCAL( void )
+  otv_x_y_ux_sy( FT_Bytes       table,
+                 OTV_Validator  valid );
+
+#define ChainPosClassRule  otv_x_ux_y_uy_z_uz_p_sp, "ChainPosClassRule"
+#define ChainPosRule       otv_x_ux_y_uy_z_uz_p_sp, "ChainPosRule"
+#define ChainSubClassRule  otv_x_ux_y_uy_z_uz_p_sp, "ChainSubClassRule"
+#define ChainSubRule       otv_x_ux_y_uy_z_uz_p_sp, "ChainSubRule"
+
+  FT_LOCAL( void )
+  otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes       table,
+                           OTV_Validator  valid );
+
+#define ContextPosFormat2    otv_u_O_O_x_Onx, "ContextPosFormat2"
+#define ContextSubstFormat2  otv_u_O_O_x_Onx, "ContextSubstFormat2"
+
+  FT_LOCAL( void )
+  otv_u_O_O_x_Onx( FT_Bytes       table,
+                   OTV_Validator  valid );
+
+#define ContextPosFormat3    otv_u_x_y_Ox_sy, "ContextPosFormat3"
+#define ContextSubstFormat3  otv_u_x_y_Ox_sy, "ContextSubstFormat3"
+
+  FT_LOCAL( void )
+  otv_u_x_y_Ox_sy( FT_Bytes       table,
+                   OTV_Validator  valid );
+
+#define ChainContextPosFormat2    otv_u_O_O_O_O_x_Onx, "ChainContextPosFormat2"
+#define ChainContextSubstFormat2  otv_u_O_O_O_O_x_Onx, "ChainContextSubstFormat2"
+
+  FT_LOCAL( void )
+  otv_u_O_O_O_O_x_Onx( FT_Bytes       table,
+                       OTV_Validator  valid );
+
+#define ChainContextPosFormat3    otv_u_x_Ox_y_Oy_z_Oz_p_sp, "ChainContextPosFormat3"
+#define ChainContextSubstFormat3  otv_u_x_Ox_y_Oy_z_Oz_p_sp, "ChainContextSubstFormat3"
+
+  FT_LOCAL( void )
+  otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes       table,
+                             OTV_Validator  valid );
+
+
+  FT_LOCAL( FT_UInt )
+  otv_GSUBGPOS_get_Lookup_count( FT_Bytes  table );
+
+  FT_LOCAL( FT_UInt )
+  otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes  table );
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* __OTVCOMMN_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otverror.h
@@ -1,0 +1,43 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otverror.h                                                             */
+/*                                                                         */
+/*    OpenType validation module error codes (specification only).         */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the OpenType validation module error      */
+  /* enumeration constants.                                                */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __OTVERROR_H__
+#define __OTVERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  OTV_Err_
+#define FT_ERR_BASE    FT_Mod_Err_OTV
+
+#define FT_KEEP_ERR_PREFIX
+
+#include FT_ERRORS_H
+
+#endif /* __OTVERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvgdef.c
@@ -1,0 +1,219 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvgdef.c                                                              */
+/*                                                                         */
+/*    OpenType GDEF table validation (body).                               */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "otvalid.h"
+#include "otvcommn.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_otvgdef
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      UTILITY FUNCTIONS                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define AttachList    otv_O_x_Ox, "AttachList"
+#define LigCaretList  otv_O_x_Ox, "LigCaretList"
+
+  /* sets valid->extra1 (0)           */
+
+  static void
+  otv_O_x_Ox( FT_Bytes       table,
+              OTV_Validator  valid )
+  {
+    FT_Bytes           p = table;
+    FT_Bytes           Coverage;
+    FT_UInt            GlyphCount;
+    OTV_Validate_Func  func;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 4 );
+    Coverage   = table + FT_NEXT_USHORT( p );
+    GlyphCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
+
+    otv_Coverage_validate( Coverage, valid );
+    if ( GlyphCount != otv_Coverage_get_count( Coverage ) )
+      FT_INVALID_DATA;
+
+    OTV_LIMIT_CHECK( GlyphCount * 2 );
+
+    valid->nesting_level++;
+    func          = valid->func[valid->nesting_level];
+    valid->extra1 = 0;
+
+    for ( ; GlyphCount > 0; GlyphCount-- )
+      func( table + FT_NEXT_USHORT( p ), valid );
+
+    valid->nesting_level--;
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       LIGATURE CARETS                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define  CaretValue  otv_CaretValue_validate, "CaretValue"
+
+  static void
+  otv_CaretValue_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   CaretValueFormat;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 4 );
+
+    CaretValueFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format = %d)\n", CaretValueFormat ));
+
+    switch ( CaretValueFormat )
+    {
+    case 1:     /* CaretValueFormat1 */
+      /* skip Coordinate, no test */
+      break;
+
+    case 2:     /* CaretValueFormat2 */
+      /* skip CaretValuePoint, no test */
+      break;
+
+    case 3:     /* CaretValueFormat3 */
+      p += 2;   /* skip Coordinate */
+
+      OTV_LIMIT_CHECK( 2 );
+
+      /* DeviceTable */
+      otv_Device_validate( table + FT_NEXT_USHORT( p ), valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         GDEF TABLE                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  otv_GDEF_validate( FT_Bytes      table,
+                     FT_Bytes      gsub,
+                     FT_Bytes      gpos,
+                     FT_Validator  ftvalid )
+  {
+    OTV_ValidatorRec  validrec;
+    OTV_Validator     valid = &validrec;
+    FT_Bytes          p     = table;
+    FT_UInt           table_size;
+    FT_Bool           need_MarkAttachClassDef;
+
+    OTV_OPTIONAL_TABLE( GlyphClassDef );
+    OTV_OPTIONAL_TABLE( AttachListOffset );
+    OTV_OPTIONAL_TABLE( LigCaretListOffset );
+    OTV_OPTIONAL_TABLE( MarkAttachClassDef );
+
+
+    valid->root = ftvalid;
+
+    FT_TRACE3(( "validating GDEF table\n" ));
+    OTV_INIT;
+
+    OTV_LIMIT_CHECK( 12 );
+
+    if ( FT_NEXT_ULONG( p ) != 0x10000UL )          /* Version */
+      FT_INVALID_FORMAT;
+
+    /* MarkAttachClassDef has been added to the OpenType */
+    /* specification without increasing GDEF's version,  */
+    /* so we use this ugly hack to find out whether the  */
+    /* table is needed actually.                         */
+
+    need_MarkAttachClassDef =
+      otv_GSUBGPOS_have_MarkAttachmentType_flag( gsub ) ||
+      otv_GSUBGPOS_have_MarkAttachmentType_flag( gpos );
+
+    if ( need_MarkAttachClassDef )
+      table_size = 12;              /* OpenType >= 1.2 */
+    else
+      table_size = 10;              /* OpenType < 1.2  */
+
+    OTV_OPTIONAL_OFFSET( GlyphClassDef );
+    OTV_SIZE_CHECK( GlyphClassDef );
+    if ( GlyphClassDef )
+      otv_ClassDef_validate( table + GlyphClassDef, valid );
+
+    OTV_OPTIONAL_OFFSET( AttachListOffset );
+    OTV_SIZE_CHECK( AttachListOffset );
+    if ( AttachListOffset )
+    {
+      OTV_NEST2( AttachList, AttachPoint );
+      OTV_RUN( table + AttachListOffset, valid );
+    }
+
+    OTV_OPTIONAL_OFFSET( LigCaretListOffset );
+    OTV_SIZE_CHECK( LigCaretListOffset );
+    if ( LigCaretListOffset )
+    {
+      OTV_NEST3( LigCaretList, LigGlyph, CaretValue );
+      OTV_RUN( table + LigCaretListOffset, valid );
+    }
+
+    if ( need_MarkAttachClassDef )
+    {
+      OTV_OPTIONAL_OFFSET( MarkAttachClassDef );
+      OTV_SIZE_CHECK( MarkAttachClassDef );
+      if ( MarkAttachClassDef )
+        otv_ClassDef_validate( table + MarkAttachClassDef, valid );
+    }
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvgpos.c
@@ -1,0 +1,1013 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvgpos.c                                                              */
+/*                                                                         */
+/*    OpenType GPOS table validation (body).                               */
+/*                                                                         */
+/*  Copyright 2002, 2004 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "otvalid.h"
+#include "otvcommn.h"
+#include "otvgpos.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_otvgpos
+
+
+  static void
+  otv_Anchor_validate( FT_Bytes       table,
+                       OTV_Validator  valid );
+
+  static void
+  otv_MarkArray_validate( FT_Bytes       table,
+                          OTV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      UTILITY FUNCTIONS                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define BaseArray       otv_x_sxy, "BaseArray"
+#define LigatureAttach  otv_x_sxy, "LigatureAttach"
+#define Mark2Array      otv_x_sxy, "Mark2Array"
+
+  /* uses valid->extra1 (counter)                             */
+  /* uses valid->extra2 (boolean to handle NULL anchor field) */
+
+  static void
+  otv_x_sxy( FT_Bytes       table,
+             OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   Count, count1, table_size;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 2 );
+
+    OTV_TRACE(( " (Count = %d)\n", Count ));
+
+    Count = FT_NEXT_USHORT( p );
+
+    OTV_LIMIT_CHECK( Count * valid->extra1 * 2 );
+
+    table_size = Count * valid->extra1 * 2 + 2;
+
+    for ( ; Count > 0; Count-- )
+      for ( count1 = valid->extra1; count1 > 0; count1-- )
+      {
+        OTV_OPTIONAL_TABLE( anchor_offset );
+
+
+        OTV_OPTIONAL_OFFSET( anchor_offset );
+
+        if ( valid->extra2 )
+        {
+          OTV_SIZE_CHECK( anchor_offset );
+          if ( anchor_offset )
+            otv_Anchor_validate( table + anchor_offset, valid );
+        }        
+        else  
+          otv_Anchor_validate( table + anchor_offset, valid );
+      }
+
+    OTV_EXIT;
+  }
+
+
+#define MarkBasePosFormat1  otv_u_O_O_u_O_O, "MarkBasePosFormat1"
+#define MarkLigPosFormat1   otv_u_O_O_u_O_O, "MarkLigPosFormat1"
+#define MarkMarkPosFormat1  otv_u_O_O_u_O_O, "MarkMarkPosFormat1"
+
+  /* sets valid->extra1 (class count) */
+
+  static void
+  otv_u_O_O_u_O_O( FT_Bytes       table,
+                   OTV_Validator  valid )
+  {
+    FT_Bytes           p = table;
+    FT_UInt            Coverage1, Coverage2, ClassCount;
+    FT_UInt            Array1, Array2;
+    OTV_Validate_Func  func;
+
+
+    OTV_ENTER;
+
+    p += 2;     /* skip PosFormat */
+
+    OTV_LIMIT_CHECK( 10 );
+    Coverage1  = FT_NEXT_USHORT( p );
+    Coverage2  = FT_NEXT_USHORT( p );
+    ClassCount = FT_NEXT_USHORT( p );
+    Array1     = FT_NEXT_USHORT( p );
+    Array2     = FT_NEXT_USHORT( p );
+
+    otv_Coverage_validate( table + Coverage1, valid );
+    otv_Coverage_validate( table + Coverage2, valid );
+
+    otv_MarkArray_validate( table + Array1, valid );
+
+    valid->nesting_level++;
+    func          = valid->func[valid->nesting_level];    
+    valid->extra1 = ClassCount;
+
+    func( table + Array2, valid );
+
+    valid->nesting_level--;
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        VALUE RECORDS                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static FT_UInt
+  otv_value_length( FT_UInt  format )
+  {
+    FT_UInt  count;
+
+
+    count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 );
+    count = ( ( count  & 0xCC ) >> 2 ) + ( count  & 0x33 );
+    count = ( ( count  & 0xF0 ) >> 4 ) + ( count  & 0x0F );
+
+    return count * 2;
+  }
+
+
+  /* uses valid->extra3 (pointer to base table) */
+
+  static void
+  otv_ValueRecord_validate( FT_Bytes       table,
+                            FT_UInt        format,
+                            OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   count;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    FT_Int    loop;
+    FT_ULong  res = 0;
+
+
+    OTV_NAME_ENTER( "ValueRecord" );
+
+    /* display `format' in dual representation */
+    for ( loop = 7; loop >= 0; loop-- )
+    {
+      res <<= 4;
+      res  += ( format >> loop ) & 1;
+    }
+
+    OTV_TRACE(( " (format 0b%08lx)\n", res ));
+#endif
+
+    if ( format >= 0x100 )
+      FT_INVALID_DATA;
+
+    for ( count = 4; count > 0; count-- )
+    {
+      if ( format & 1 )
+      {
+        /* XPlacement, YPlacement, XAdvance, YAdvance */
+        OTV_LIMIT_CHECK( 2 );
+        p += 2;
+      }
+
+      format >>= 1;
+    }
+
+    for ( count = 4; count > 0; count-- )
+    {
+      if ( format & 1 )
+      {
+        FT_UInt   table_size;
+
+        OTV_OPTIONAL_TABLE( device );
+
+
+        /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */
+        OTV_LIMIT_CHECK( 2 );
+        OTV_OPTIONAL_OFFSET( device );
+
+        /* XXX: this value is usually too small, especially if the current */
+        /* ValueRecord is part of an array -- getting the correct table    */
+        /* size is probably not worth the trouble                          */
+
+        table_size = p - valid->extra3;
+
+        OTV_SIZE_CHECK( device );
+        if ( device )
+          otv_Device_validate( valid->extra3 + device, valid );
+      }
+      format >>= 1;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           ANCHORS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  otv_Anchor_validate( FT_Bytes       table,
+                       OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   AnchorFormat;
+
+
+    OTV_NAME_ENTER( "Anchor");
+
+    OTV_LIMIT_CHECK( 6 );
+    AnchorFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", AnchorFormat ));
+
+    p += 4;     /* skip XCoordinate and YCoordinate */
+
+    switch ( AnchorFormat )
+    {
+    case 1:
+      break;
+
+    case 2:
+      OTV_LIMIT_CHECK( 2 );  /* AnchorPoint */
+      break;
+
+    case 3:
+      {
+        FT_UInt   table_size;
+
+        OTV_OPTIONAL_TABLE( XDeviceTable );
+        OTV_OPTIONAL_TABLE( YDeviceTable );
+
+
+        OTV_LIMIT_CHECK( 4 );
+        OTV_OPTIONAL_OFFSET( XDeviceTable );
+        OTV_OPTIONAL_OFFSET( YDeviceTable );
+
+        table_size = 6 + 4;
+
+        OTV_SIZE_CHECK( XDeviceTable );
+        if ( XDeviceTable )
+          otv_Device_validate( table + XDeviceTable, valid );
+
+        OTV_SIZE_CHECK( YDeviceTable );
+        if ( YDeviceTable )
+          otv_Device_validate( table + YDeviceTable, valid );
+      }
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         MARK ARRAYS                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  otv_MarkArray_validate( FT_Bytes       table,
+                          OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   MarkCount;
+
+
+    OTV_NAME_ENTER( "MarkArray" );
+
+    OTV_LIMIT_CHECK( 2 );
+    MarkCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (MarkCount = %d)\n", MarkCount ));
+
+    OTV_LIMIT_CHECK( MarkCount * 4 );
+
+    /* MarkRecord */
+    for ( ; MarkCount > 0; MarkCount-- )
+    {
+      p += 2;   /* skip Class */
+      /* MarkAnchor */
+      otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid );
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 1                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra3 (pointer to base table) */
+
+  static void
+  otv_SinglePos_validate( FT_Bytes       table,
+                          OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "SinglePos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    valid->extra3 = table;
+
+    switch ( PosFormat )
+    {
+    case 1:     /* SinglePosFormat1 */
+      {
+        FT_UInt  Coverage, ValueFormat;
+
+
+        OTV_LIMIT_CHECK( 4 );
+        Coverage    = FT_NEXT_USHORT( p );
+        ValueFormat = FT_NEXT_USHORT( p );
+
+        otv_Coverage_validate( table + Coverage, valid );
+        otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */
+      }
+      break;
+
+    case 2:     /* SinglePosFormat2 */
+      {
+        FT_UInt  Coverage, ValueFormat, ValueCount, len_value;
+
+
+        OTV_LIMIT_CHECK( 6 );
+        Coverage    = FT_NEXT_USHORT( p );
+        ValueFormat = FT_NEXT_USHORT( p );
+        ValueCount  = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (ValueCount = %d)\n", ValueCount ));
+
+        len_value = otv_value_length( ValueFormat );
+
+        otv_Coverage_validate( table + Coverage, valid );
+
+        OTV_LIMIT_CHECK( ValueCount * len_value );
+
+        /* Value */
+        for ( ; ValueCount > 0; ValueCount-- )
+        {
+          otv_ValueRecord_validate( p, ValueFormat, valid );
+          p += len_value;
+        }
+      }
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 2                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  otv_PairSet_validate( FT_Bytes       table,
+                        FT_UInt        format1,
+                        FT_UInt        format2,
+                        OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   value_len1, value_len2, PairValueCount;
+
+
+    OTV_NAME_ENTER( "PairSet" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PairValueCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount ));
+
+    value_len1 = otv_value_length( format1 );
+    value_len2 = otv_value_length( format2 );
+
+    OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) );
+
+    /* PairValueRecord */
+    for ( ; PairValueCount > 0; PairValueCount-- )
+    {
+      p += 2;       /* skip SecondGlyph */
+
+      if ( format1 )
+        otv_ValueRecord_validate( p, format1, valid ); /* Value1 */
+      p += value_len1;
+
+      if ( format2 )
+        otv_ValueRecord_validate( p, format2, valid ); /* Value2 */
+      p += value_len2;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /* sets valid->extra3 (pointer to base table) */
+
+  static void
+  otv_PairPos_validate( FT_Bytes       table,
+                        OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "PairPos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    valid->extra3 = table;
+
+    switch ( PosFormat )
+    {
+    case 1:     /* PairPosFormat1 */
+      {
+        FT_UInt  Coverage, ValueFormat1, ValueFormat2, PairSetCount;
+
+
+        OTV_LIMIT_CHECK( 8 );
+        Coverage     = FT_NEXT_USHORT( p );
+        ValueFormat1 = FT_NEXT_USHORT( p );
+        ValueFormat2 = FT_NEXT_USHORT( p );
+        PairSetCount = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount ));
+
+        otv_Coverage_validate( table + Coverage, valid );
+
+        OTV_LIMIT_CHECK( PairSetCount * 2 );
+
+        /* PairSetOffset */
+        for ( ; PairSetCount > 0; PairSetCount-- )
+          otv_PairSet_validate( table + FT_NEXT_USHORT( p ),
+                                ValueFormat1, ValueFormat2, valid );
+      }
+      break;
+
+    case 2:     /* PairPosFormat2 */
+      {
+        FT_UInt  Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2;
+        FT_UInt  ClassCount1, ClassCount2, len_value1, len_value2, count;
+
+
+        OTV_LIMIT_CHECK( 14 );
+        Coverage     = FT_NEXT_USHORT( p );
+        ValueFormat1 = FT_NEXT_USHORT( p );
+        ValueFormat2 = FT_NEXT_USHORT( p );
+        ClassDef1    = FT_NEXT_USHORT( p );
+        ClassDef2    = FT_NEXT_USHORT( p );
+        ClassCount1  = FT_NEXT_USHORT( p );
+        ClassCount2  = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 ));
+        OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 ));
+
+        len_value1 = otv_value_length( ValueFormat1 );
+        len_value2 = otv_value_length( ValueFormat2 );
+
+        otv_Coverage_validate( table + Coverage, valid );
+        otv_ClassDef_validate( table + ClassDef1, valid );
+        otv_ClassDef_validate( table + ClassDef2, valid );
+
+        OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
+                     ( len_value1 + len_value2 ) );
+
+        /* Class1Record */
+        for ( ; ClassCount1 > 0; ClassCount1-- )
+        {
+          /* Class2Record */
+          for ( count = ClassCount2; count > 0; count-- )
+          {
+            if ( ValueFormat1 )
+              /* Value1 */
+              otv_ValueRecord_validate( p, ValueFormat1, valid );
+            p += len_value1;
+
+            if ( ValueFormat2 )
+              /* Value2 */
+              otv_ValueRecord_validate( p, ValueFormat2, valid );
+            p += len_value2;
+          }
+        }
+      }
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 3                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  otv_CursivePos_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "CursivePos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    switch ( PosFormat )
+    {
+    case 1:     /* CursivePosFormat1 */
+      {
+        FT_UInt   table_size;
+        FT_UInt   Coverage, EntryExitCount;
+
+        OTV_OPTIONAL_TABLE( EntryAnchor );
+        OTV_OPTIONAL_TABLE( ExitAnchor  );
+
+
+        OTV_LIMIT_CHECK( 4 );
+        Coverage       = FT_NEXT_USHORT( p );
+        EntryExitCount = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
+
+        otv_Coverage_validate( table + Coverage, valid );
+
+        OTV_LIMIT_CHECK( EntryExitCount * 4 );
+
+        table_size = EntryExitCount * 4 + 4;
+
+        /* EntryExitRecord */
+        for ( ; EntryExitCount > 0; EntryExitCount-- )
+        {
+          OTV_OPTIONAL_OFFSET( EntryAnchor );
+          OTV_OPTIONAL_OFFSET( ExitAnchor  );
+
+          OTV_SIZE_CHECK( EntryAnchor );
+          if ( EntryAnchor )
+            otv_Anchor_validate( table + EntryAnchor, valid );
+
+          OTV_SIZE_CHECK( ExitAnchor );
+          if ( ExitAnchor )
+            otv_Anchor_validate( table + ExitAnchor, valid );
+        }
+      }
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 4                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra2 (0) */
+
+  static void
+  otv_MarkBasePos_validate( FT_Bytes       table,
+                            OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "MarkBasePos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    switch ( PosFormat )
+    {
+    case 1:
+      valid->extra2 = 0;
+      OTV_NEST2( MarkBasePosFormat1, BaseArray );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 5                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra2 (1) */
+
+  static void
+  otv_MarkLigPos_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "MarkLigPos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    switch ( PosFormat )
+    {
+    case 1:
+      valid->extra2 = 1;
+      OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 6                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra2 (0) */
+
+  static void
+  otv_MarkMarkPos_validate( FT_Bytes       table,
+                            OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "MarkMarkPos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    switch ( PosFormat )
+    {
+    case 1:
+      valid->extra2 = 0;
+      OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 7                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra1 (lookup count) */
+
+  static void
+  otv_ContextPos_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "ContextPos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    switch ( PosFormat )
+    {
+    case 1:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      valid->extra1 = valid->lookup_count;
+      OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 2:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 3:
+      OTV_NEST1( ContextPosFormat3 );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 8                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra1 (lookup count) */
+
+  static void
+  otv_ChainContextPos_validate( FT_Bytes       table,
+                                OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "ChainContextPos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    switch ( PosFormat )
+    {
+    case 1:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      valid->extra1 = valid->lookup_count;
+      OTV_NEST3( ChainContextPosFormat1,
+                 ChainPosRuleSet, ChainPosRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 2:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      OTV_NEST3( ChainContextPosFormat2,
+                 ChainPosClassSet, ChainPosClassRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 3:
+      OTV_NEST1( ChainContextPosFormat3 );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     GPOS LOOKUP TYPE 9                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* uses valid->type_funcs */
+
+  static void
+  otv_ExtensionPos_validate( FT_Bytes       table,
+                             OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   PosFormat;
+
+
+    OTV_NAME_ENTER( "ExtensionPos" );
+
+    OTV_LIMIT_CHECK( 2 );
+    PosFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", PosFormat ));
+
+    switch ( PosFormat )
+    {
+    case 1:     /* ExtensionPosFormat1 */
+      {
+        FT_UInt            ExtensionLookupType, ExtensionOffset;
+        OTV_Validate_Func  validate;
+
+
+        OTV_LIMIT_CHECK( 6 );
+        ExtensionLookupType = FT_NEXT_USHORT( p );
+        ExtensionOffset     = FT_NEXT_ULONG( p );
+
+        if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
+          FT_INVALID_DATA;
+
+        validate = valid->type_funcs[ExtensionLookupType - 1];
+        validate( table + ExtensionOffset, valid );
+      }
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  static OTV_Validate_Func  otv_gpos_validate_funcs[9] =
+  {
+    otv_SinglePos_validate,
+    otv_PairPos_validate,
+    otv_CursivePos_validate,
+    otv_MarkBasePos_validate,
+    otv_MarkLigPos_validate,
+    otv_MarkMarkPos_validate,
+    otv_ContextPos_validate,
+    otv_ChainContextPos_validate,
+    otv_ExtensionPos_validate
+  };
+
+
+  /* sets valid->type_count */
+  /* sets valid->type_funcs */
+
+  FT_LOCAL_DEF( void )
+  otv_GPOS_subtable_validate( FT_Bytes       table,
+                              OTV_Validator  valid )
+  {
+    valid->type_count = 9;
+    valid->type_funcs = otv_gpos_validate_funcs;
+
+    otv_Lookup_validate( table, valid );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          GPOS TABLE                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->glyph_count */
+
+  FT_LOCAL_DEF( void )
+  otv_GPOS_validate( FT_Bytes      table,
+                     FT_UInt       glyph_count,
+                     FT_Validator  ftvalid )
+  {
+    OTV_ValidatorRec  validrec;
+    OTV_Validator     valid = &validrec;
+    FT_Bytes          p     = table;
+    FT_UInt           ScriptList, FeatureList, LookupList;
+
+
+    valid->root = ftvalid;
+
+    FT_TRACE3(( "validating GPOS table\n" ));
+    OTV_INIT;
+
+    OTV_LIMIT_CHECK( 10 );
+
+    if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
+      FT_INVALID_DATA;
+
+    ScriptList  = FT_NEXT_USHORT( p );
+    FeatureList = FT_NEXT_USHORT( p );
+    LookupList  = FT_NEXT_USHORT( p );
+
+    valid->type_count  = 9;
+    valid->type_funcs  = otv_gpos_validate_funcs;
+    valid->glyph_count = glyph_count;
+
+    otv_LookupList_validate( table + LookupList,
+                             valid );
+    otv_FeatureList_validate( table + FeatureList, table + LookupList,
+                              valid );
+    otv_ScriptList_validate( table + ScriptList, table + FeatureList,
+                             valid );
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvgpos.h
@@ -1,0 +1,36 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvgpos.h                                                              */
+/*                                                                         */
+/*    OpenType GPOS table validator (specification).                       */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __OTVGPOS_H__
+#define __OTVGPOS_H__
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( void )
+  otv_GPOS_subtable_validate( FT_Bytes       table,
+                              OTV_Validator  valid );
+
+
+FT_END_HEADER
+
+#endif /* __OTVGPOS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvgsub.c
@@ -1,0 +1,584 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvgsub.c                                                              */
+/*                                                                         */
+/*    OpenType GSUB table validation (body).                               */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "otvalid.h"
+#include "otvcommn.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_otvgsub
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  GSUB LOOKUP TYPE 1                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* uses valid->glyph_count */
+
+  static void
+  otv_SingleSubst_validate( FT_Bytes       table,
+                            OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   SubstFormat;
+
+
+    OTV_NAME_ENTER( "SingleSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:     /* SingleSubstFormat1 */
+      {
+        FT_Bytes  Coverage;
+        FT_Int    DeltaGlyphID;
+        FT_Long   idx;
+
+
+        OTV_LIMIT_CHECK( 4 );
+        Coverage     = table + FT_NEXT_USHORT( p );
+        DeltaGlyphID = FT_NEXT_SHORT( p );
+
+        otv_Coverage_validate( Coverage, valid );
+
+        idx = otv_Coverage_get_first( Coverage ) + DeltaGlyphID;
+        if ( idx < 0 )
+          FT_INVALID_DATA;
+
+        idx = otv_Coverage_get_last( Coverage ) + DeltaGlyphID;
+        if ( (FT_UInt)idx >= valid->glyph_count )
+          FT_INVALID_DATA;
+      }
+      break;
+
+    case 2:     /* SingleSubstFormat2 */
+      {
+        FT_UInt  Coverage, GlyphCount;
+
+
+        OTV_LIMIT_CHECK( 4 );
+        Coverage   = FT_NEXT_USHORT( p );
+        GlyphCount = FT_NEXT_USHORT( p );
+
+        OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
+
+        otv_Coverage_validate( table + Coverage, valid );
+
+        OTV_LIMIT_CHECK( GlyphCount * 2 );
+
+        /* Substitute */
+        for ( ; GlyphCount > 0; GlyphCount-- )
+          if ( FT_NEXT_USHORT( p ) >= valid->glyph_count )
+            FT_INVALID_DATA;
+      }
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  GSUB LOOKUP TYPE 2                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra1 (glyph count) */
+
+  static void
+  otv_MultipleSubst_validate( FT_Bytes       table,
+                              OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   SubstFormat;
+
+
+    OTV_NAME_ENTER( "MultipleSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:
+      valid->extra1 = valid->glyph_count;
+      OTV_NEST2( MultipleSubstFormat1, Sequence );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 3                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra1 (glyph count) */
+
+  static void
+  otv_AlternateSubst_validate( FT_Bytes       table,
+                               OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   SubstFormat;
+
+
+    OTV_NAME_ENTER( "AlternateSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:
+      valid->extra1 = valid->glyph_count;
+      OTV_NEST2( AlternateSubstFormat1, AlternateSet );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 4                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define Ligature  otv_Ligature_validate, "Ligature"
+
+  /* uses valid->glyph_count */
+
+  static void
+  otv_Ligature_validate( FT_Bytes       table,
+                         OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   LigatureGlyph, CompCount;
+
+
+    OTV_ENTER;
+
+    OTV_LIMIT_CHECK( 4 );
+    LigatureGlyph = FT_NEXT_USHORT( p );
+    if ( LigatureGlyph >= valid->glyph_count )
+      FT_INVALID_DATA;
+
+    CompCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (CompCount = %d)\n", CompCount ));
+
+    if ( CompCount == 0 )
+      FT_INVALID_DATA;
+
+    CompCount--;
+
+    OTV_LIMIT_CHECK( CompCount * 2 );     /* Component */
+
+    /* no need to check the Component glyph indices */
+
+    OTV_EXIT;
+  }
+
+
+  static void
+  otv_LigatureSubst_validate( FT_Bytes       table,
+                              OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   SubstFormat;
+
+
+    OTV_NAME_ENTER( "LigatureSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:
+      OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  GSUB LOOKUP TYPE 5                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra1 (lookup count) */
+
+  static void
+  otv_ContextSubst_validate( FT_Bytes       table,
+                             OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   SubstFormat;
+
+
+    OTV_NAME_ENTER( "ContextSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      valid->extra1 = valid->lookup_count;
+      OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 2:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 3:
+      OTV_NEST1( ContextSubstFormat3 );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 6                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->extra1 (lookup count)            */
+
+  static void
+  otv_ChainContextSubst_validate( FT_Bytes       table,
+                                  OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   SubstFormat;
+
+
+    OTV_NAME_ENTER( "ChainContextSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      valid->extra1 = valid->lookup_count;
+      OTV_NEST3( ChainContextSubstFormat1,
+                 ChainSubRuleSet, ChainSubRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 2:
+      /* no need to check glyph indices/classes used as input for these */
+      /* context rules since even invalid glyph indices/classes return  */
+      /* meaningful results                                             */
+
+      OTV_NEST3( ChainContextSubstFormat2,
+                 ChainSubClassSet, ChainSubClassRule );
+      OTV_RUN( table, valid );
+      break;
+
+    case 3:
+      OTV_NEST1( ChainContextSubstFormat3 );
+      OTV_RUN( table, valid );
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 7                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* uses valid->type_funcs */
+
+  static void
+  otv_ExtensionSubst_validate( FT_Bytes       table,
+                               OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   SubstFormat;
+
+
+    OTV_NAME_ENTER( "ExtensionSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:     /* ExtensionSubstFormat1 */
+      {
+        FT_UInt            ExtensionLookupType, ExtensionOffset;
+        OTV_Validate_Func  validate;
+
+
+        OTV_LIMIT_CHECK( 6 );
+        ExtensionLookupType = FT_NEXT_USHORT( p );
+        ExtensionOffset     = FT_NEXT_ULONG( p );
+
+        if ( ExtensionLookupType == 0 ||
+             ExtensionLookupType == 7 ||
+             ExtensionLookupType > 8  )
+          FT_INVALID_DATA;
+
+        validate = valid->type_funcs[ExtensionLookupType - 1];
+        validate( table + ExtensionOffset, valid );
+      }
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GSUB LOOKUP TYPE 8                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* uses valid->glyph_count */
+
+  static void
+  otv_ReverseChainSingleSubst_validate( FT_Bytes       table,
+                                        OTV_Validator  valid )
+  {
+    FT_Bytes  p = table, Coverage;
+    FT_UInt   SubstFormat;
+    FT_UInt   BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount;
+
+
+    OTV_NAME_ENTER( "ReverseChainSingleSubst" );
+
+    OTV_LIMIT_CHECK( 2 );
+    SubstFormat = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (format %d)\n", SubstFormat ));
+
+    switch ( SubstFormat )
+    {
+    case 1:     /* ReverseChainSingleSubstFormat1 */
+      OTV_LIMIT_CHECK( 4 );
+      Coverage            = table + FT_NEXT_USHORT( p );
+      BacktrackGlyphCount = FT_NEXT_USHORT( p );
+
+      OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount ));
+
+      otv_Coverage_validate( Coverage, valid );
+
+      OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 );
+
+      for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- )
+        otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid );
+
+      LookaheadGlyphCount = FT_NEXT_USHORT( p );
+
+      OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount ));
+
+      OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 );
+
+      for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- )
+        otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid );
+
+      GlyphCount = FT_NEXT_USHORT( p );
+
+      OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
+
+      if ( GlyphCount != otv_Coverage_get_count( Coverage ) )
+        FT_INVALID_DATA;
+
+      OTV_LIMIT_CHECK( GlyphCount * 2 );
+
+      /* Substitute */
+      for ( ; GlyphCount > 0; GlyphCount-- )
+        if ( FT_NEXT_USHORT( p ) >= valid->glyph_count )
+          FT_INVALID_DATA;
+
+      break;
+
+    default:
+      FT_INVALID_DATA;
+    }
+
+    OTV_EXIT;
+  }
+
+
+  static OTV_Validate_Func  otv_gsub_validate_funcs[8] =
+  {
+    otv_SingleSubst_validate,
+    otv_MultipleSubst_validate,
+    otv_AlternateSubst_validate,
+    otv_LigatureSubst_validate,
+    otv_ContextSubst_validate,
+    otv_ChainContextSubst_validate,
+    otv_ExtensionSubst_validate,
+    otv_ReverseChainSingleSubst_validate
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          GSUB TABLE                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* sets valid->type_count  */
+  /* sets valid->type_funcs  */
+  /* sets valid->glyph_count */
+
+  FT_LOCAL_DEF( void )
+  otv_GSUB_validate( FT_Bytes      table,
+                     FT_UInt       glyph_count,
+                     FT_Validator  ftvalid )
+  {
+    OTV_ValidatorRec  validrec;
+    OTV_Validator     valid = &validrec;
+    FT_Bytes          p     = table;
+    FT_UInt           ScriptList, FeatureList, LookupList;
+
+
+    valid->root = ftvalid;
+
+    FT_TRACE3(( "validating GSUB table\n" ));
+    OTV_INIT;
+
+    OTV_LIMIT_CHECK( 10 );
+
+    if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
+      FT_INVALID_DATA;
+
+    ScriptList  = FT_NEXT_USHORT( p );
+    FeatureList = FT_NEXT_USHORT( p );
+    LookupList  = FT_NEXT_USHORT( p );
+
+    valid->type_count  = 8;
+    valid->type_funcs  = otv_gsub_validate_funcs;
+    valid->glyph_count = glyph_count;
+
+    otv_LookupList_validate( table + LookupList,
+                             valid );
+    otv_FeatureList_validate( table + FeatureList, table + LookupList,
+                              valid );
+    otv_ScriptList_validate( table + ScriptList, table + FeatureList,
+                             valid );
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvjstf.c
@@ -1,0 +1,258 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvjstf.c                                                              */
+/*                                                                         */
+/*    OpenType JSTF table validation (body).                               */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "otvalid.h"
+#include "otvcommn.h"
+#include "otvgpos.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_otvjstf
+
+
+#define JstfPriority  otv_JstfPriority_validate, "JstfPriority"
+#define JstfLookup    otv_GPOS_subtable_validate, ""
+
+  /* uses valid->extra1 (GSUB lookup count) */
+  /* uses valid->extra2 (GPOS lookup count) */
+  /* sets valid->extra1 (counter)           */
+
+  static void
+  otv_JstfPriority_validate( FT_Bytes       table,
+                             OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   table_size;
+    FT_UInt   gsub_lookup_count, gpos_lookup_count;
+
+    OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB  );
+    OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB );
+    OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS  );
+    OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS );
+    OTV_OPTIONAL_TABLE( ExtensionEnableGSUB  );
+    OTV_OPTIONAL_TABLE( ExtensionDisableGSUB );
+    OTV_OPTIONAL_TABLE( ExtensionEnableGPOS  );
+    OTV_OPTIONAL_TABLE( ExtensionDisableGPOS );
+    OTV_OPTIONAL_TABLE( ShrinkageJstfMax );
+    OTV_OPTIONAL_TABLE( ExtensionJstfMax );
+
+
+    OTV_ENTER;
+    OTV_TRACE(( "JstfPriority table\n" ));
+
+    OTV_LIMIT_CHECK( 20 );
+
+    gsub_lookup_count = valid->extra1;
+    gpos_lookup_count = valid->extra2;
+
+    table_size = 20;
+
+    valid->extra1 = gsub_lookup_count;
+    
+    OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB );
+    OTV_SIZE_CHECK( ShrinkageEnableGSUB );
+    if ( ShrinkageEnableGSUB )
+      otv_x_ux( table + ShrinkageEnableGSUB, valid );
+
+    OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB );
+    OTV_SIZE_CHECK( ShrinkageDisableGSUB );
+    if ( ShrinkageDisableGSUB )
+      otv_x_ux( table + ShrinkageDisableGSUB, valid );
+
+    valid->extra1 = gpos_lookup_count;
+
+    OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS );
+    OTV_SIZE_CHECK( ShrinkageEnableGPOS );
+    if ( ShrinkageEnableGPOS )
+      otv_x_ux( table + ShrinkageEnableGPOS, valid );
+
+    OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS );
+    OTV_SIZE_CHECK( ShrinkageDisableGPOS );
+    if ( ShrinkageDisableGPOS )
+      otv_x_ux( table + ShrinkageDisableGPOS, valid );
+
+    OTV_OPTIONAL_OFFSET( ShrinkageJstfMax );
+    OTV_SIZE_CHECK( ShrinkageJstfMax );
+    if ( ShrinkageJstfMax )
+    {
+      /* XXX: check lookup types? */
+      OTV_NEST2( JstfMax, JstfLookup );
+      OTV_RUN( table + ShrinkageJstfMax, valid );
+    }
+
+    valid->extra1 = gsub_lookup_count;
+
+    OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB );
+    OTV_SIZE_CHECK( ExtensionEnableGSUB );
+    if ( ExtensionEnableGSUB )
+      otv_x_ux( table + ExtensionEnableGSUB, valid );
+
+    OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB );
+    OTV_SIZE_CHECK( ExtensionDisableGSUB );
+    if ( ExtensionDisableGSUB )
+      otv_x_ux( table + ExtensionDisableGSUB, valid );
+
+    valid->extra1 = gpos_lookup_count;
+
+    OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS );
+    OTV_SIZE_CHECK( ExtensionEnableGPOS );
+    if ( ExtensionEnableGPOS )
+      otv_x_ux( table + ExtensionEnableGPOS, valid );
+
+    OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS );
+    OTV_SIZE_CHECK( ExtensionDisableGPOS );
+    if ( ExtensionDisableGPOS )
+      otv_x_ux( table + ExtensionDisableGPOS, valid );
+
+    OTV_OPTIONAL_OFFSET( ExtensionJstfMax );
+    OTV_SIZE_CHECK( ExtensionJstfMax );
+    if ( ExtensionJstfMax )
+    {
+      /* XXX: check lookup types? */
+      OTV_NEST2( JstfMax, JstfLookup );
+      OTV_RUN( table + ExtensionJstfMax, valid );
+    }
+
+    valid->extra1 = gsub_lookup_count;
+    valid->extra2 = gpos_lookup_count;
+
+    OTV_EXIT;
+  }
+
+
+  /* sets valid->extra (glyph count)               */
+  /* sets valid->func1 (otv_JstfPriority_validate) */
+
+  static void
+  otv_JstfScript_validate( FT_Bytes       table,
+                           OTV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   table_size;
+    FT_UInt   JstfLangSysCount;
+
+    OTV_OPTIONAL_TABLE( ExtGlyph );
+    OTV_OPTIONAL_TABLE( DefJstfLangSys );
+
+
+    OTV_NAME_ENTER( "JstfScript" );
+
+    OTV_LIMIT_CHECK( 6 );
+    OTV_OPTIONAL_OFFSET( ExtGlyph );
+    OTV_OPTIONAL_OFFSET( DefJstfLangSys );
+    JstfLangSysCount = FT_NEXT_USHORT( p );
+
+    OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount ));
+
+    table_size = JstfLangSysCount * 6 + 6;
+
+    OTV_SIZE_CHECK( ExtGlyph );
+    if ( ExtGlyph )
+    {
+      valid->extra1 = valid->glyph_count;
+      OTV_NEST1( ExtenderGlyph );
+      OTV_RUN( table + ExtGlyph, valid );
+    }
+
+    OTV_SIZE_CHECK( DefJstfLangSys );
+    if ( DefJstfLangSys )
+    {
+      OTV_NEST2( JstfLangSys, JstfPriority );
+      OTV_RUN( table + DefJstfLangSys, valid );
+    }
+
+    OTV_LIMIT_CHECK( 6 * JstfLangSysCount );
+
+    /* JstfLangSysRecord */
+    OTV_NEST2( JstfLangSys, JstfPriority );
+    for ( ; JstfLangSysCount > 0; JstfLangSysCount-- )
+    {
+      p += 4;       /* skip JstfLangSysTag */
+
+      OTV_RUN( table + FT_NEXT_USHORT( p ), valid );
+    }
+
+    OTV_EXIT;
+  }
+
+
+  /* sets valid->extra1 (GSUB lookup count) */
+  /* sets valid->extra2 (GPOS lookup count) */
+  /* sets valid->glyph_count                */
+
+  FT_LOCAL_DEF( void )
+  otv_JSTF_validate( FT_Bytes      table,
+                     FT_Bytes      gsub,
+                     FT_Bytes      gpos,
+                     FT_UInt       glyph_count,
+                     FT_Validator  ftvalid )
+  {
+    OTV_ValidatorRec  validrec;
+    OTV_Validator     valid = &validrec;
+    FT_Bytes          p     = table;
+    FT_UInt           JstfScriptCount;
+
+
+    valid->root = ftvalid;
+
+    FT_TRACE3(( "validating JSTF table\n" ));
+    OTV_INIT;
+
+    OTV_LIMIT_CHECK( 6 );
+
+    if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
+      FT_INVALID_DATA;
+
+    JstfScriptCount = FT_NEXT_USHORT( p );
+
+    FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount ));
+
+    OTV_LIMIT_CHECK( JstfScriptCount * 6 );
+
+    if ( gsub )
+      valid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub );
+    else
+      valid->extra1 = 0;
+
+    if ( gpos )
+      valid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos );
+    else
+      valid->extra2 = 0;
+
+    valid->glyph_count = glyph_count;
+
+    /* JstfScriptRecord */
+    for ( ; JstfScriptCount > 0; JstfScriptCount-- )
+    {
+      p += 4;       /* skip JstfScriptTag */
+
+      /* JstfScript */
+      otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), valid );
+    }
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvmod.c
@@ -1,0 +1,227 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvmod.c                                                               */
+/*                                                                         */
+/*    FreeType's OpenType validation module implementation (body).         */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_TRUETYPE_TABLES_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_OPENTYPE_VALIDATE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_OPENTYPE_VALIDATE_H
+
+#include "otvmod.h"
+#include "otvalid.h"
+#include "otvcommn.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_otvmodule
+
+
+  static FT_Error
+  otv_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 == OTV_Err_Table_Missing )
+      return OTV_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;
+  }
+
+
+  static FT_Error
+  otv_validate( FT_Face    face,
+                FT_UInt    ot_flags,
+                FT_Bytes  *ot_base,
+                FT_Bytes  *ot_gdef,
+                FT_Bytes  *ot_gpos,
+                FT_Bytes  *ot_gsub,
+                FT_Bytes  *ot_jstf )
+  {
+    FT_Error         error = OTV_Err_Ok;
+    FT_Byte          *base, *gdef, *gpos, *gsub, *jstf;
+    FT_ULong         len_base, len_gdef, len_gpos, len_gsub, len_jstf;
+    FT_ValidatorRec  valid;
+
+
+    base     = gdef     = gpos     = gsub     = jstf     = NULL;
+    len_base = len_gdef = len_gpos = len_gsub = len_jstf = 0;
+
+    /* load tables */
+
+    if ( ot_flags & FT_VALIDATE_BASE )
+    {
+      error = otv_load_table( face, TTAG_BASE, &base, &len_base );
+      if ( error )
+        goto Exit;
+    }
+
+    if ( ot_flags & FT_VALIDATE_GDEF )
+    {
+      error = otv_load_table( face, TTAG_GDEF, &gdef, &len_gdef );
+      if ( error )
+        goto Exit;
+    }
+
+    if ( ot_flags & FT_VALIDATE_GPOS )
+    {
+      error = otv_load_table( face, TTAG_GPOS, &gpos, &len_gpos );
+      if ( error )
+        goto Exit;
+    }
+
+    if ( ot_flags & FT_VALIDATE_GSUB )
+    {
+      error = otv_load_table( face, TTAG_GSUB, &gsub, &len_gsub );
+      if ( error )
+        goto Exit;
+    }
+
+    if ( ot_flags & FT_VALIDATE_JSTF )
+    {
+      error = otv_load_table( face, TTAG_JSTF, &jstf, &len_jstf );
+      if ( error )
+        goto Exit;
+    }
+
+    /* validate tables */
+
+    if ( base )
+    {
+      ft_validator_init( &valid, base, base + len_base, FT_VALIDATE_DEFAULT );
+      if ( ft_setjmp( valid.jump_buffer ) == 0 )
+        otv_BASE_validate( base, &valid );
+      error = valid.error;
+      if ( error )
+        goto Exit;
+    }
+
+    if ( gpos )
+    {
+      ft_validator_init( &valid, gpos, gpos + len_gpos, FT_VALIDATE_DEFAULT );
+      if (ft_setjmp( valid.jump_buffer ) == 0 )
+        otv_GPOS_validate( gpos, face->num_glyphs, &valid );
+      error = valid.error;
+      if ( error )
+        goto Exit;
+    }
+
+    if ( gsub )
+    {
+      ft_validator_init( &valid, gsub, gsub + len_gsub, FT_VALIDATE_DEFAULT );
+      if ( ft_setjmp( valid.jump_buffer ) == 0 )
+        otv_GSUB_validate( gsub, face->num_glyphs, &valid );
+      error = valid.error;
+      if ( error )
+        goto Exit;
+    }
+
+    if ( gdef )
+    {
+      ft_validator_init( &valid, gdef, gdef + len_gdef, FT_VALIDATE_DEFAULT );
+      if ( ft_setjmp( valid.jump_buffer ) == 0 )
+        otv_GDEF_validate( gdef, gsub, gpos, &valid );
+      error = valid.error;
+      if ( error )
+        goto Exit;
+    }
+
+    if ( jstf )
+    {
+      ft_validator_init( &valid, jstf, jstf + len_jstf, FT_VALIDATE_DEFAULT );
+      if ( ft_setjmp( valid.jump_buffer ) == 0 )
+        otv_JSTF_validate( jstf, gsub, gpos, face->num_glyphs, &valid );
+      error = valid.error;
+      if ( error )
+        goto Exit;
+    }
+
+    *ot_base = (FT_Bytes)base;
+    *ot_gdef = (FT_Bytes)gdef;
+    *ot_gpos = (FT_Bytes)gpos;
+    *ot_gsub = (FT_Bytes)gsub;
+    *ot_jstf = (FT_Bytes)jstf;
+
+  Exit:
+    return error;
+  }
+
+
+  static
+  const FT_Service_OTvalidateRec  otvalid_interface = 
+  {
+    otv_validate
+  };
+
+
+  static
+  const FT_ServiceDescRec  otvalid_services[] = 
+  {
+    { FT_SERVICE_ID_OPENTYPE_VALIDATE, &otvalid_interface },
+    { NULL, NULL }
+  };
+
+
+  static FT_Pointer
+  otvalid_get_service( FT_Module    module,
+                       const char*  service_id )
+  {
+    FT_UNUSED( module );
+
+    return ft_service_list_lookup( otvalid_services, service_id );
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Module_Class  otv_module_class =
+  {
+    0,
+    sizeof( FT_ModuleRec ),
+    "otvalid",
+    0x10000L,
+    0x20000L,
+
+    0,              /* module-specific interface */
+
+    (FT_Module_Constructor)0,
+    (FT_Module_Destructor) 0,
+    (FT_Module_Requester)  otvalid_get_service
+  };
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/otvmod.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otvmod.h                                                               */
+/*                                                                         */
+/*    FreeType's OpenType validation module implementation                 */
+/*    (specification).                                                     */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __OTVMOD_H__
+#define __OTVMOD_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Module_Class )  otv_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __OTVMOD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/otvalid/rules.mk
@@ -1,0 +1,77 @@
+#
+# FreeType 2 OpenType validation driver configuration rules
+#
+
+
+# Copyright 2004 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+# OTV driver directory
+#
+OTV_DIR := $(SRC_DIR)/otvalid
+
+
+# compilation flags for the driver
+#
+OTV_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(OTV_DIR))
+
+
+# OTV driver sources (i.e., C files)
+#
+OTV_DRV_SRC := $(OTV_DIR)/otvbase.c  \
+               $(OTV_DIR)/otvcommn.c \
+               $(OTV_DIR)/otvgdef.c  \
+               $(OTV_DIR)/otvgpos.c  \
+               $(OTV_DIR)/otvgsub.c  \
+               $(OTV_DIR)/otvjstf.c  \
+               $(OTV_DIR)/otvmod.c
+
+# OTV driver headers
+#
+OTV_DRV_H := $(OTV_DIR)/otvalid.h \
+             $(OTV_DIR)/otverror.h  \
+             $(OTV_DIR)/otvcommn.h \
+             $(OTV_DIR)/otvgpos.h \
+             $(OTV_DIR)/otvmod.h
+
+
+# OTV driver object(s)
+#
+#   OTV_DRV_OBJ_M is used during `multi' builds.
+#   OTV_DRV_OBJ_S is used during `single' builds.
+#
+OTV_DRV_OBJ_M := $(OTV_DRV_SRC:$(OTV_DIR)/%.c=$(OBJ_DIR)/%.$O)
+OTV_DRV_OBJ_S := $(OBJ_DIR)/otvalid.$O
+
+# OTV driver source file for single build
+#
+OTV_DRV_SRC_S := $(OTV_DIR)/otvalid.c
+
+
+# OTV driver - single object
+#
+$(OTV_DRV_OBJ_S): $(OTV_DRV_SRC_S) $(OTV_DRV_SRC) \
+                   $(FREETYPE_H) $(OTV_DRV_H)
+	$(OTV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(OTV_DRV_SRC_S))
+
+
+# OTV driver - multiple objects
+#
+$(OBJ_DIR)/%.$O: $(OTV_DIR)/%.c $(FREETYPE_H) $(OTV_DRV_H)
+	$(OTV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(OTV_DRV_OBJ_S)
+DRV_OBJS_M += $(OTV_DRV_OBJ_M)
+
+
+# EOF