1 | /**************************************************************************** |
2 | * |
3 | * otvjstf.c |
4 | * |
5 | * OpenType JSTF table validation (body). |
6 | * |
7 | * Copyright (C) 2004-2023 by |
8 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
9 | * |
10 | * This file is part of the FreeType project, and may only be used, |
11 | * modified, and distributed under the terms of the FreeType project |
12 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
13 | * this file you indicate that you have read the license and |
14 | * understand and accept it fully. |
15 | * |
16 | */ |
17 | |
18 | |
19 | #include "otvalid.h" |
20 | #include "otvcommn.h" |
21 | #include "otvgpos.h" |
22 | |
23 | |
24 | /************************************************************************** |
25 | * |
26 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
27 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
28 | * messages during execution. |
29 | */ |
30 | #undef FT_COMPONENT |
31 | #define FT_COMPONENT otvjstf |
32 | |
33 | |
34 | #define JstfPriorityFunc otv_JstfPriority_validate |
35 | #define JstfLookupFunc otv_GPOS_subtable_validate |
36 | |
37 | /* uses otvalid->extra1 (GSUB lookup count) */ |
38 | /* uses otvalid->extra2 (GPOS lookup count) */ |
39 | /* sets otvalid->extra1 (counter) */ |
40 | |
41 | static void |
42 | otv_JstfPriority_validate( FT_Bytes table, |
43 | OTV_Validator otvalid ) |
44 | { |
45 | FT_Bytes p = table; |
46 | FT_UInt table_size; |
47 | FT_UInt gsub_lookup_count, gpos_lookup_count; |
48 | |
49 | OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB ); |
50 | OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB ); |
51 | OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS ); |
52 | OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS ); |
53 | OTV_OPTIONAL_TABLE( ExtensionEnableGSUB ); |
54 | OTV_OPTIONAL_TABLE( ExtensionDisableGSUB ); |
55 | OTV_OPTIONAL_TABLE( ExtensionEnableGPOS ); |
56 | OTV_OPTIONAL_TABLE( ExtensionDisableGPOS ); |
57 | OTV_OPTIONAL_TABLE( ShrinkageJstfMax ); |
58 | OTV_OPTIONAL_TABLE( ExtensionJstfMax ); |
59 | |
60 | |
61 | OTV_ENTER; |
62 | OTV_TRACE(( "JstfPriority table\n" )); |
63 | |
64 | OTV_LIMIT_CHECK( 20 ); |
65 | |
66 | gsub_lookup_count = otvalid->extra1; |
67 | gpos_lookup_count = otvalid->extra2; |
68 | |
69 | table_size = 20; |
70 | |
71 | otvalid->extra1 = gsub_lookup_count; |
72 | |
73 | OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB ); |
74 | OTV_SIZE_CHECK( ShrinkageEnableGSUB ); |
75 | if ( ShrinkageEnableGSUB ) |
76 | otv_x_ux( table + ShrinkageEnableGSUB, otvalid ); |
77 | |
78 | OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB ); |
79 | OTV_SIZE_CHECK( ShrinkageDisableGSUB ); |
80 | if ( ShrinkageDisableGSUB ) |
81 | otv_x_ux( table + ShrinkageDisableGSUB, otvalid ); |
82 | |
83 | otvalid->extra1 = gpos_lookup_count; |
84 | |
85 | OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS ); |
86 | OTV_SIZE_CHECK( ShrinkageEnableGPOS ); |
87 | if ( ShrinkageEnableGPOS ) |
88 | otv_x_ux( table + ShrinkageEnableGPOS, otvalid ); |
89 | |
90 | OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS ); |
91 | OTV_SIZE_CHECK( ShrinkageDisableGPOS ); |
92 | if ( ShrinkageDisableGPOS ) |
93 | otv_x_ux( table + ShrinkageDisableGPOS, otvalid ); |
94 | |
95 | OTV_OPTIONAL_OFFSET( ShrinkageJstfMax ); |
96 | OTV_SIZE_CHECK( ShrinkageJstfMax ); |
97 | if ( ShrinkageJstfMax ) |
98 | { |
99 | /* XXX: check lookup types? */ |
100 | OTV_NEST2( JstfMax, JstfLookup ); |
101 | OTV_RUN( table + ShrinkageJstfMax, otvalid ); |
102 | } |
103 | |
104 | otvalid->extra1 = gsub_lookup_count; |
105 | |
106 | OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB ); |
107 | OTV_SIZE_CHECK( ExtensionEnableGSUB ); |
108 | if ( ExtensionEnableGSUB ) |
109 | otv_x_ux( table + ExtensionEnableGSUB, otvalid ); |
110 | |
111 | OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB ); |
112 | OTV_SIZE_CHECK( ExtensionDisableGSUB ); |
113 | if ( ExtensionDisableGSUB ) |
114 | otv_x_ux( table + ExtensionDisableGSUB, otvalid ); |
115 | |
116 | otvalid->extra1 = gpos_lookup_count; |
117 | |
118 | OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS ); |
119 | OTV_SIZE_CHECK( ExtensionEnableGPOS ); |
120 | if ( ExtensionEnableGPOS ) |
121 | otv_x_ux( table + ExtensionEnableGPOS, otvalid ); |
122 | |
123 | OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS ); |
124 | OTV_SIZE_CHECK( ExtensionDisableGPOS ); |
125 | if ( ExtensionDisableGPOS ) |
126 | otv_x_ux( table + ExtensionDisableGPOS, otvalid ); |
127 | |
128 | OTV_OPTIONAL_OFFSET( ExtensionJstfMax ); |
129 | OTV_SIZE_CHECK( ExtensionJstfMax ); |
130 | if ( ExtensionJstfMax ) |
131 | { |
132 | /* XXX: check lookup types? */ |
133 | OTV_NEST2( JstfMax, JstfLookup ); |
134 | OTV_RUN( table + ExtensionJstfMax, otvalid ); |
135 | } |
136 | |
137 | otvalid->extra1 = gsub_lookup_count; |
138 | otvalid->extra2 = gpos_lookup_count; |
139 | |
140 | OTV_EXIT; |
141 | } |
142 | |
143 | |
144 | /* sets otvalid->extra (glyph count) */ |
145 | /* sets otvalid->func1 (otv_JstfPriority_validate) */ |
146 | |
147 | static void |
148 | otv_JstfScript_validate( FT_Bytes table, |
149 | OTV_Validator otvalid ) |
150 | { |
151 | FT_Bytes p = table; |
152 | FT_UInt table_size; |
153 | FT_UInt JstfLangSysCount; |
154 | |
155 | OTV_OPTIONAL_TABLE( ExtGlyph ); |
156 | OTV_OPTIONAL_TABLE( DefJstfLangSys ); |
157 | |
158 | |
159 | OTV_NAME_ENTER( "JstfScript" ); |
160 | |
161 | OTV_LIMIT_CHECK( 6 ); |
162 | OTV_OPTIONAL_OFFSET( ExtGlyph ); |
163 | OTV_OPTIONAL_OFFSET( DefJstfLangSys ); |
164 | JstfLangSysCount = FT_NEXT_USHORT( p ); |
165 | |
166 | OTV_TRACE(( " (JstfLangSysCount = %d)\n" , JstfLangSysCount )); |
167 | |
168 | table_size = JstfLangSysCount * 6 + 6; |
169 | |
170 | OTV_SIZE_CHECK( ExtGlyph ); |
171 | if ( ExtGlyph ) |
172 | { |
173 | otvalid->extra1 = otvalid->glyph_count; |
174 | OTV_NEST1( ExtenderGlyph ); |
175 | OTV_RUN( table + ExtGlyph, otvalid ); |
176 | } |
177 | |
178 | OTV_SIZE_CHECK( DefJstfLangSys ); |
179 | if ( DefJstfLangSys ) |
180 | { |
181 | OTV_NEST2( JstfLangSys, JstfPriority ); |
182 | OTV_RUN( table + DefJstfLangSys, otvalid ); |
183 | } |
184 | |
185 | OTV_LIMIT_CHECK( 6 * JstfLangSysCount ); |
186 | |
187 | /* JstfLangSysRecord */ |
188 | OTV_NEST2( JstfLangSys, JstfPriority ); |
189 | for ( ; JstfLangSysCount > 0; JstfLangSysCount-- ) |
190 | { |
191 | p += 4; /* skip JstfLangSysTag */ |
192 | |
193 | OTV_RUN( table + FT_NEXT_USHORT( p ), otvalid ); |
194 | } |
195 | |
196 | OTV_EXIT; |
197 | } |
198 | |
199 | |
200 | /* sets otvalid->extra1 (GSUB lookup count) */ |
201 | /* sets otvalid->extra2 (GPOS lookup count) */ |
202 | /* sets otvalid->glyph_count */ |
203 | |
204 | FT_LOCAL_DEF( void ) |
205 | otv_JSTF_validate( FT_Bytes table, |
206 | FT_Bytes gsub, |
207 | FT_Bytes gpos, |
208 | FT_UInt glyph_count, |
209 | FT_Validator ftvalid ) |
210 | { |
211 | OTV_ValidatorRec otvalidrec; |
212 | OTV_Validator otvalid = &otvalidrec; |
213 | FT_Bytes p = table; |
214 | FT_UInt JstfScriptCount; |
215 | |
216 | |
217 | otvalid->root = ftvalid; |
218 | |
219 | |
220 | FT_TRACE3(( "validating JSTF table\n" )); |
221 | OTV_INIT; |
222 | |
223 | OTV_LIMIT_CHECK( 6 ); |
224 | |
225 | if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ |
226 | FT_INVALID_FORMAT; |
227 | |
228 | JstfScriptCount = FT_NEXT_USHORT( p ); |
229 | |
230 | FT_TRACE3(( " (JstfScriptCount = %d)\n" , JstfScriptCount )); |
231 | |
232 | OTV_LIMIT_CHECK( JstfScriptCount * 6 ); |
233 | |
234 | if ( gsub ) |
235 | otvalid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub ); |
236 | else |
237 | otvalid->extra1 = 0; |
238 | |
239 | if ( gpos ) |
240 | otvalid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos ); |
241 | else |
242 | otvalid->extra2 = 0; |
243 | |
244 | otvalid->glyph_count = glyph_count; |
245 | |
246 | /* JstfScriptRecord */ |
247 | for ( ; JstfScriptCount > 0; JstfScriptCount-- ) |
248 | { |
249 | p += 4; /* skip JstfScriptTag */ |
250 | |
251 | /* JstfScript */ |
252 | otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), otvalid ); |
253 | } |
254 | |
255 | FT_TRACE4(( "\n" )); |
256 | } |
257 | |
258 | |
259 | /* END */ |
260 | |