1 | /**************************************************************************** |
2 | * |
3 | * gxvmorx.c |
4 | * |
5 | * TrueTypeGX/AAT morx table validation (body). |
6 | * |
7 | * Copyright (C) 2005-2023 by |
8 | * suzuki toshiya, Masatake YAMATO, Red Hat K.K., |
9 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
10 | * |
11 | * This file is part of the FreeType project, and may only be used, |
12 | * modified, and distributed under the terms of the FreeType project |
13 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
14 | * this file you indicate that you have read the license and |
15 | * understand and accept it fully. |
16 | * |
17 | */ |
18 | |
19 | /**************************************************************************** |
20 | * |
21 | * gxvalid is derived from both gxlayout module and otvalid module. |
22 | * Development of gxlayout is supported by the Information-technology |
23 | * Promotion Agency(IPA), Japan. |
24 | * |
25 | */ |
26 | |
27 | |
28 | #include "gxvmorx.h" |
29 | |
30 | |
31 | /************************************************************************** |
32 | * |
33 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
34 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
35 | * messages during execution. |
36 | */ |
37 | #undef FT_COMPONENT |
38 | #define FT_COMPONENT gxvmorx |
39 | |
40 | |
41 | static void |
42 | gxv_morx_subtables_validate( FT_Bytes table, |
43 | FT_Bytes limit, |
44 | FT_UShort nSubtables, |
45 | GXV_Validator gxvalid ) |
46 | { |
47 | FT_Bytes p = table; |
48 | |
49 | GXV_Validate_Func fmt_funcs_table[] = |
50 | { |
51 | gxv_morx_subtable_type0_validate, /* 0 */ |
52 | gxv_morx_subtable_type1_validate, /* 1 */ |
53 | gxv_morx_subtable_type2_validate, /* 2 */ |
54 | NULL, /* 3 */ |
55 | gxv_morx_subtable_type4_validate, /* 4 */ |
56 | gxv_morx_subtable_type5_validate, /* 5 */ |
57 | |
58 | }; |
59 | |
60 | FT_UShort i; |
61 | |
62 | |
63 | GXV_NAME_ENTER( "subtables in a chain" ); |
64 | |
65 | for ( i = 0; i < nSubtables; i++ ) |
66 | { |
67 | GXV_Validate_Func func; |
68 | |
69 | FT_ULong length; |
70 | FT_ULong coverage; |
71 | #ifdef GXV_LOAD_UNUSED_VARS |
72 | FT_ULong subFeatureFlags; |
73 | #endif |
74 | FT_ULong type; |
75 | FT_ULong rest; |
76 | |
77 | |
78 | GXV_LIMIT_CHECK( 4 + 4 + 4 ); |
79 | length = FT_NEXT_ULONG( p ); |
80 | coverage = FT_NEXT_ULONG( p ); |
81 | #ifdef GXV_LOAD_UNUSED_VARS |
82 | subFeatureFlags = FT_NEXT_ULONG( p ); |
83 | #else |
84 | p += 4; |
85 | #endif |
86 | |
87 | GXV_TRACE(( "validating chain subtable %d/%d (%lu bytes)\n" , |
88 | i + 1, nSubtables, length )); |
89 | |
90 | type = coverage & 0x0007; |
91 | rest = length - ( 4 + 4 + 4 ); |
92 | GXV_LIMIT_CHECK( rest ); |
93 | |
94 | /* morx coverage consists of mort_coverage & 16bit padding */ |
95 | gxv_mort_coverage_validate( (FT_UShort)( ( coverage >> 16 ) | coverage ), |
96 | gxvalid ); |
97 | if ( type > 5 ) |
98 | FT_INVALID_FORMAT; |
99 | |
100 | func = fmt_funcs_table[type]; |
101 | if ( !func ) |
102 | GXV_TRACE(( "morx type %lu is reserved\n" , type )); |
103 | |
104 | func( p, p + rest, gxvalid ); |
105 | |
106 | /* TODO: subFeatureFlags should be unique in a table? */ |
107 | p += rest; |
108 | } |
109 | |
110 | gxvalid->subtable_length = (FT_ULong)( p - table ); |
111 | |
112 | GXV_EXIT; |
113 | } |
114 | |
115 | |
116 | static void |
117 | gxv_morx_chain_validate( FT_Bytes table, |
118 | FT_Bytes limit, |
119 | GXV_Validator gxvalid ) |
120 | { |
121 | FT_Bytes p = table; |
122 | #ifdef GXV_LOAD_UNUSED_VARS |
123 | FT_ULong defaultFlags; |
124 | #endif |
125 | FT_ULong chainLength; |
126 | FT_ULong nFeatureFlags; |
127 | FT_ULong nSubtables; |
128 | |
129 | |
130 | GXV_NAME_ENTER( "morx chain header" ); |
131 | |
132 | GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 ); |
133 | #ifdef GXV_LOAD_UNUSED_VARS |
134 | defaultFlags = FT_NEXT_ULONG( p ); |
135 | #else |
136 | p += 4; |
137 | #endif |
138 | chainLength = FT_NEXT_ULONG( p ); |
139 | nFeatureFlags = FT_NEXT_ULONG( p ); |
140 | nSubtables = FT_NEXT_ULONG( p ); |
141 | |
142 | /* feature-array of morx is same with that of mort */ |
143 | gxv_mort_featurearray_validate( p, limit, nFeatureFlags, gxvalid ); |
144 | p += gxvalid->subtable_length; |
145 | |
146 | if ( nSubtables >= 0x10000L ) |
147 | FT_INVALID_DATA; |
148 | |
149 | gxv_morx_subtables_validate( p, table + chainLength, |
150 | (FT_UShort)nSubtables, gxvalid ); |
151 | |
152 | gxvalid->subtable_length = chainLength; |
153 | |
154 | /* TODO: defaultFlags should be compared with the flags in tables */ |
155 | |
156 | GXV_EXIT; |
157 | } |
158 | |
159 | |
160 | FT_LOCAL_DEF( void ) |
161 | gxv_morx_validate( FT_Bytes table, |
162 | FT_Face face, |
163 | FT_Validator ftvalid ) |
164 | { |
165 | GXV_ValidatorRec gxvalidrec; |
166 | GXV_Validator gxvalid = &gxvalidrec; |
167 | FT_Bytes p = table; |
168 | FT_Bytes limit = 0; |
169 | FT_ULong version; |
170 | FT_ULong nChains; |
171 | FT_ULong i; |
172 | |
173 | |
174 | gxvalid->root = ftvalid; |
175 | gxvalid->face = face; |
176 | |
177 | FT_TRACE3(( "validating `morx' table\n" )); |
178 | GXV_INIT; |
179 | |
180 | GXV_LIMIT_CHECK( 4 + 4 ); |
181 | version = FT_NEXT_ULONG( p ); |
182 | nChains = FT_NEXT_ULONG( p ); |
183 | |
184 | if ( version != 0x00020000UL ) |
185 | FT_INVALID_FORMAT; |
186 | |
187 | for ( i = 0; i < nChains; i++ ) |
188 | { |
189 | GXV_TRACE(( "validating chain %lu/%lu\n" , i + 1, nChains )); |
190 | GXV_32BIT_ALIGNMENT_VALIDATE( p - table ); |
191 | gxv_morx_chain_validate( p, limit, gxvalid ); |
192 | p += gxvalid->subtable_length; |
193 | } |
194 | |
195 | FT_TRACE4(( "\n" )); |
196 | } |
197 | |
198 | |
199 | /* END */ |
200 | |