summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Lemberg <wl@gnu.org>2004-09-10 14:39:00 +0000
committerWerner Lemberg <wl@gnu.org>2004-09-10 14:39:00 +0000
commitee95b6f0d487cb31e90170032ab39d120258052e (patch)
treeebaa47a39da43bde99c9bd49322640803c9ae3ca
parent2c1e57096f90cd7e5798c06c4dc4700aa913b2e6 (diff)
downloadfreetype2-ee95b6f0d487cb31e90170032ab39d120258052e.tar.gz
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.
-rw-r--r--ChangeLog28
-rw-r--r--docs/CHANGES5
-rw-r--r--include/freetype/config/ftheader.h17
-rw-r--r--include/freetype/config/ftmodule.h2
-rw-r--r--include/freetype/freetype.h2
-rw-r--r--include/freetype/ftbdf.h8
-rw-r--r--include/freetype/ftchapters.h13
-rw-r--r--include/freetype/ftgzip.h4
-rw-r--r--include/freetype/ftimage.h2
-rw-r--r--include/freetype/ftlzw.h2
-rw-r--r--include/freetype/ftmac.h2
-rw-r--r--include/freetype/ftotval.h159
-rw-r--r--include/freetype/ftpfr.h6
-rw-r--r--include/freetype/ftsizes.h6
-rw-r--r--include/freetype/ftstroke.h2
-rw-r--r--include/freetype/ftwinfnt.h6
-rw-r--r--include/freetype/internal/ftserv.h25
-rw-r--r--include/freetype/internal/fttrace.h35
-rw-r--r--include/freetype/internal/ftvalid.h4
-rw-r--r--include/freetype/internal/services/svotval.h53
-rw-r--r--include/freetype/tttables.h2
-rw-r--r--src/base/Jamfile2
-rw-r--r--src/base/descrip.mms2
-rw-r--r--src/base/ftotval.c72
-rw-r--r--src/base/rules.mk1
-rw-r--r--src/otvalid/Jamfile21
-rw-r--r--src/otvalid/descrip.mms23
-rw-r--r--src/otvalid/module.mk22
-rw-r--r--src/otvalid/otvalid.c30
-rw-r--r--src/otvalid/otvalid.h72
-rw-r--r--src/otvalid/otvbase.c318
-rw-r--r--src/otvalid/otvcommn.c1052
-rw-r--r--src/otvalid/otvcommn.h442
-rw-r--r--src/otvalid/otverror.h43
-rw-r--r--src/otvalid/otvgdef.c219
-rw-r--r--src/otvalid/otvgpos.c1013
-rw-r--r--src/otvalid/otvgpos.h36
-rw-r--r--src/otvalid/otvgsub.c584
-rw-r--r--src/otvalid/otvjstf.c258
-rw-r--r--src/otvalid/otvmod.c227
-rw-r--r--src/otvalid/otvmod.h39
-rw-r--r--src/otvalid/rules.mk77
42 files changed, 4884 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index 2ab8d3878..6938bbca5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2004-09-09 Werner Lemberg <wl@gnu.org>
+
+ 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 <wl@gnu.org>
* 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...
diff --git a/docs/CHANGES b/docs/CHANGES
index 9ca43f96e..5bcadd588 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -23,6 +23,11 @@ LATEST CHANGES BETWEEN 2.1.10 and 2.1.9
- 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
diff --git a/include/freetype/config/ftheader.h b/include/freetype/config/ftheader.h
index b996a7a6f..7b18813cc 100644
--- 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: */
@@ -529,6 +532,20 @@
/* */
#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>
+
+
/* */
#define FT_TRIGONOMETRY_H <freetype/fttrigon.h>
diff --git a/include/freetype/config/ftmodule.h b/include/freetype/config/ftmodule.h
index c00a489f7..762d4af30 100644
--- a/include/freetype/config/ftmodule.h
+++ b/include/freetype/config/ftmodule.h
@@ -16,4 +16,4 @@ FT_USE_MODULE(ft_smooth_lcdv_renderer_class)
FT_USE_MODULE(t42_driver_class)
FT_USE_MODULE(pfr_driver_class)
FT_USE_MODULE(winfnt_driver_class)
-
+FT_USE_MODULE(otv_module_class)
diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
index d9f934487..dac5c451f 100644
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -2883,7 +2883,7 @@ FT_BEGIN_HEADER
/* Computations */
/* */
/* <Abstract> */
- /* Crunching fixed numbers and vectors */
+ /* Crunching fixed numbers and vectors. */
/* */
/* <Description> */
/* This section contains various functions used to perform */
diff --git a/include/freetype/ftbdf.h b/include/freetype/ftbdf.h
index aa411440d..493bca511 100644
--- 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 @@ FT_BEGIN_HEADER
/* 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. */
/* */
/*************************************************************************/
diff --git a/include/freetype/ftchapters.h b/include/freetype/ftchapters.h
index c134ec122..462859986 100644
--- 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 */
/* */
/***************************************************************************/
diff --git a/include/freetype/ftgzip.h b/include/freetype/ftgzip.h
index 5d7228bb4..ded96bec6 100644
--- 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 @@ FT_BEGIN_HEADER
/* GZIP Streams */
/* */
/* <Abstract> */
- /* Using gzip-compressed font files */
+ /* Using gzip-compressed font files. */
/* */
/* <Description> */
/* This section contains the declaration of Gzip-specific functions. */
diff --git a/include/freetype/ftimage.h b/include/freetype/ftimage.h
index 4682a4cad..c67d67bc8 100644
--- a/include/freetype/ftimage.h
+++ b/include/freetype/ftimage.h
@@ -772,7 +772,7 @@ FT_BEGIN_HEADER
/* raster */
/* */
/* <Title> */
- /* Scanline converter */
+ /* Scanline Converter */
/* */
/* <Abstract> */
/* How vectorial outlines are converted into bitmaps and pixmaps. */
diff --git a/include/freetype/ftlzw.h b/include/freetype/ftlzw.h
index a0a042ea0..2ebd50080 100644
--- a/include/freetype/ftlzw.h
+++ b/include/freetype/ftlzw.h
@@ -40,7 +40,7 @@ FT_BEGIN_HEADER
/* LZW Streams */
/* */
/* <Abstract> */
- /* Using LZW-compressed font files */
+ /* Using LZW-compressed font files. */
/* */
/* <Description> */
/* This section contains the declaration of LZW-specific functions. */
diff --git a/include/freetype/ftmac.h b/include/freetype/ftmac.h
index 78ed77947..4ebf716eb 100644
--- a/include/freetype/ftmac.h
+++ b/include/freetype/ftmac.h
@@ -41,7 +41,7 @@ FT_BEGIN_HEADER
/* mac_specific */
/* */
/* <Title> */
- /* Mac-Specific Interface */
+ /* Mac Specific Interface */
/* */
/* <Abstract> */
/* Only available on the Macintosh. */
diff --git a/include/freetype/ftotval.h b/include/freetype/ftotval.h
new file mode 100644
index 000000000..58b778f08
--- /dev/null
+++ b/include/freetype/ftotval.h
@@ -0,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 */
diff --git a/include/freetype/ftpfr.h b/include/freetype/ftpfr.h
index c9a567544..248165952 100644
--- 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 @@ FT_BEGIN_HEADER
/* 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_BEGIN_HEADER
FT_END_HEADER
-#endif /* __FTBDF_H__ */
+#endif /* __FTPFR_H__ */
/* END */
diff --git a/include/freetype/ftsizes.h b/include/freetype/ftsizes.h
index f0ec91599..9abd94bc4 100644
--- 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 @@ FT_BEGIN_HEADER
/* 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 */
diff --git a/include/freetype/ftstroke.h b/include/freetype/ftstroke.h
index 0d958007e..c6c96deed 100644
--- a/include/freetype/ftstroke.h
+++ b/include/freetype/ftstroke.h
@@ -30,7 +30,7 @@ FT_BEGIN_HEADER
/************************************************************************
*
* <Section>
- * glyph stroker
+ * glyph_stroker
*
* <Title>
* Glyph Stroker
diff --git a/include/freetype/ftwinfnt.h b/include/freetype/ftwinfnt.h
index a19a12d97..355b7e904 100644
--- 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 @@ FT_BEGIN_HEADER
/* 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 */
diff --git a/include/freetype/internal/ftserv.h b/include/freetype/internal/ftserv.h
index e5ed8895b..98e0d56c6 100644
--- 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 @@ FT_BEGIN_HEADER
* 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>
/* */
diff --git a/include/freetype/internal/fttrace.h b/include/freetype/internal/fttrace.h
index a9a15a286..556a9942b 100644
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -37,17 +37,17 @@ FT_TRACE_DEF( smooth ) /* anti-aliasing raster (ftgrays.c) */
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) */
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( ttobjs ) /* TT objects manager (ttobjs.c) */
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,26 +63,26 @@ FT_TRACE_DEF( t1load )
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 )
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( cidload )
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 */
diff --git a/include/freetype/internal/ftvalid.h b/include/freetype/internal/ftvalid.h
index 4ee204d27..d52ff2f3b 100644
--- a/include/freetype/internal/ftvalid.h
+++ b/include/freetype/internal/ftvalid.h
@@ -49,7 +49,7 @@ FT_BEGIN_HEADER
/* 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 @@ FT_BEGIN_HEADER
/* 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 :: */
diff --git a/include/freetype/internal/services/svotval.h b/include/freetype/internal/services/svotval.h
new file mode 100644
index 000000000..fbe45d0dd
--- /dev/null
+++ b/include/freetype/internal/services/svotval.h
@@ -0,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 */
diff --git a/include/freetype/tttables.h b/include/freetype/tttables.h
index ccf43c68c..378eba84e 100644
--- a/include/freetype/tttables.h
+++ b/include/freetype/tttables.h
@@ -42,7 +42,7 @@ FT_BEGIN_HEADER
/* 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 */
diff --git a/src/base/Jamfile b/src/base/Jamfile
index d82e65d6d..f46e9b4c8 100644
--- a/src/base/Jamfile
+++ b/src/base/Jamfile
@@ -24,7 +24,7 @@ SubDir FT2_TOP $(FT2_SRC_DIR) base ;
#
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.
#
diff --git a/src/base/descrip.mms b/src/base/descrip.mms
index 73bad4d73..9798ef191 100644
--- 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)
diff --git a/src/base/ftotval.c b/src/base/ftotval.c
new file mode 100644
index 000000000..1364d754e
--- /dev/null
+++ b/src/base/ftotval.c
@@ -0,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 */
diff --git a/src/base/rules.mk b/src/base/rules.mk
index 8017e8589..74e66e20e 100644
--- a/src/base/rules.mk
+++ b/src/base/rules.mk
@@ -54,6 +54,7 @@ BASE_EXT_SRC := $(BASE_DIR)/ftbbox.c \
$(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 \
diff --git a/src/otvalid/Jamfile b/src/otvalid/Jamfile
new file mode 100644
index 000000000..ca650f1fa
--- /dev/null
+++ b/src/otvalid/Jamfile
@@ -0,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
diff --git a/src/otvalid/descrip.mms b/src/otvalid/descrip.mms
new file mode 100644
index 000000000..187b414c4
--- /dev/null
+++ b/src/otvalid/descrip.mms
@@ -0,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
diff --git a/src/otvalid/module.mk b/src/otvalid/module.mk
new file mode 100644
index 000000000..8f7cdf26c
--- /dev/null
+++ b/src/otvalid/module.mk
@@ -0,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
diff --git a/src/otvalid/otvalid.c b/src/otvalid/otvalid.c
new file mode 100644
index 000000000..2f85f601b
--- /dev/null
+++ b/src/otvalid/otvalid.c
@@ -0,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 */
diff --git a/src/otvalid/otvalid.h b/src/otvalid/otvalid.h
new file mode 100644
index 000000000..38f030f39
--- /dev/null
+++ b/src/otvalid/otvalid.h
@@ -0,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 */
diff --git a/src/otvalid/otvbase.c b/src/otvalid/otvbase.c
new file mode 100644
index 000000000..8ad2238d6
--- /dev/null
+++ b/src/otvalid/otvbase.c
@@ -0,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 */
diff --git a/src/otvalid/otvcommn.c b/src/otvalid/otvcommn.c
new file mode 100644
index 000000000..ec48475f1
--- /dev/null
+++ b/src/otvalid/otvcommn.c
@@ -0,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 */
diff --git a/src/otvalid/otvcommn.h b/src/otvalid/otvcommn.h
new file mode 100644
index 000000000..fa93e5aff
--- /dev/null
+++ b/src/otvalid/otvcommn.h
@@ -0,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 */
diff --git a/src/otvalid/otverror.h b/src/otvalid/otverror.h
new file mode 100644
index 000000000..dc34a5aef
--- /dev/null
+++ b/src/otvalid/otverror.h
@@ -0,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 */
diff --git a/src/otvalid/otvgdef.c b/src/otvalid/otvgdef.c
new file mode 100644
index 000000000..8df0ea58b
--- /dev/null
+++ b/src/otvalid/otvgdef.c
@@ -0,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 */
diff --git a/src/otvalid/otvgpos.c b/src/otvalid/otvgpos.c
new file mode 100644
index 000000000..372eb0633
--- /dev/null
+++ b/src/otvalid/otvgpos.c
@@ -0,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 */
diff --git a/src/otvalid/otvgpos.h b/src/otvalid/otvgpos.h
new file mode 100644
index 000000000..14ca40826
--- /dev/null
+++ b/src/otvalid/otvgpos.h
@@ -0,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 */
diff --git a/src/otvalid/otvgsub.c b/src/otvalid/otvgsub.c
new file mode 100644
index 000000000..be653bdd0
--- /dev/null
+++ b/src/otvalid/otvgsub.c
@@ -0,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 */
diff --git a/src/otvalid/otvjstf.c b/src/otvalid/otvjstf.c
new file mode 100644
index 000000000..a230b36fb
--- /dev/null
+++ b/src/otvalid/otvjstf.c
@@ -0,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 */
diff --git a/src/otvalid/otvmod.c b/src/otvalid/otvmod.c
new file mode 100644
index 000000000..146b58e04
--- /dev/null
+++ b/src/otvalid/otvmod.c
@@ -0,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 */
diff --git a/src/otvalid/otvmod.h b/src/otvalid/otvmod.h
new file mode 100644
index 000000000..1bfc1899f
--- /dev/null
+++ b/src/otvalid/otvmod.h
@@ -0,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 */
diff --git a/src/otvalid/rules.mk b/src/otvalid/rules.mk
new file mode 100644
index 000000000..48f12336f
--- /dev/null
+++ b/src/otvalid/rules.mk
@@ -0,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