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