diff --git a/ChangeLog b/ChangeLog index 2ab8d3878..6938bbca5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2004-09-09 Werner Lemberg + + 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 * src/tools/docmaker/sources.py (re_source_block_format2) : @@ -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__ + /*@***********************************************************************/ /* */ /* */ @@ -92,6 +93,7 @@ /* */ /*************************************************************************/ + /* configuration files */ /*************************************************************************/ @@ -362,6 +364,7 @@ /* */ #define FT_BDF_H + /*************************************************************************/ /* */ /* @macro: */ @@ -529,6 +532,20 @@ /* */ #define FT_SFNT_NAMES_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 + + /* */ #define FT_TRIGONOMETRY_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 */ /* */ /* */ - /* Crunching fixed numbers and vectors */ + /* Crunching fixed numbers and vectors. */ /* */ /* */ /* 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 */ /* */ /* */ - /* 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,3 +1,11 @@ +/***************************************************************************/ +/* */ +/* This file defines the structure of the FreeType reference. */ +/* It is used by the python script which generates the HTML files. */ +/* */ +/***************************************************************************/ + + /***************************************************************************/ /* */ /* <Chapter> */ @@ -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