1 | /**************************************************************************** |
2 | * |
3 | * otvbase.c |
4 | * |
5 | * OpenType BASE 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 | |
22 | |
23 | /************************************************************************** |
24 | * |
25 | * The macro FT_COMPONENT is used in trace mode. It is an implicit |
26 | * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
27 | * messages during execution. |
28 | */ |
29 | #undef FT_COMPONENT |
30 | #define FT_COMPONENT otvbase |
31 | |
32 | |
33 | static void |
34 | otv_BaseCoord_validate( FT_Bytes table, |
35 | OTV_Validator otvalid ) |
36 | { |
37 | FT_Bytes p = table; |
38 | FT_UInt BaseCoordFormat; |
39 | |
40 | |
41 | OTV_NAME_ENTER( "BaseCoord" ); |
42 | |
43 | OTV_LIMIT_CHECK( 4 ); |
44 | BaseCoordFormat = FT_NEXT_USHORT( p ); |
45 | p += 2; /* skip Coordinate */ |
46 | |
47 | OTV_TRACE(( " (format %d)\n" , BaseCoordFormat )); |
48 | |
49 | switch ( BaseCoordFormat ) |
50 | { |
51 | case 1: /* BaseCoordFormat1 */ |
52 | break; |
53 | |
54 | case 2: /* BaseCoordFormat2 */ |
55 | OTV_LIMIT_CHECK( 4 ); /* ReferenceGlyph, BaseCoordPoint */ |
56 | break; |
57 | |
58 | case 3: /* BaseCoordFormat3 */ |
59 | OTV_LIMIT_CHECK( 2 ); |
60 | /* DeviceTable */ |
61 | otv_Device_validate( table + FT_NEXT_USHORT( p ), otvalid ); |
62 | break; |
63 | |
64 | default: |
65 | FT_INVALID_FORMAT; |
66 | } |
67 | |
68 | OTV_EXIT; |
69 | } |
70 | |
71 | |
72 | static void |
73 | otv_BaseTagList_validate( FT_Bytes table, |
74 | OTV_Validator otvalid ) |
75 | { |
76 | FT_Bytes p = table; |
77 | FT_UInt BaseTagCount; |
78 | |
79 | |
80 | OTV_NAME_ENTER( "BaseTagList" ); |
81 | |
82 | OTV_LIMIT_CHECK( 2 ); |
83 | |
84 | BaseTagCount = FT_NEXT_USHORT( p ); |
85 | |
86 | OTV_TRACE(( " (BaseTagCount = %d)\n" , BaseTagCount )); |
87 | |
88 | OTV_LIMIT_CHECK( BaseTagCount * 4 ); /* BaselineTag */ |
89 | |
90 | OTV_EXIT; |
91 | } |
92 | |
93 | |
94 | static void |
95 | otv_BaseValues_validate( FT_Bytes table, |
96 | OTV_Validator otvalid ) |
97 | { |
98 | FT_Bytes p = table; |
99 | FT_UInt BaseCoordCount; |
100 | |
101 | |
102 | OTV_NAME_ENTER( "BaseValues" ); |
103 | |
104 | OTV_LIMIT_CHECK( 4 ); |
105 | |
106 | p += 2; /* skip DefaultIndex */ |
107 | BaseCoordCount = FT_NEXT_USHORT( p ); |
108 | |
109 | OTV_TRACE(( " (BaseCoordCount = %d)\n" , BaseCoordCount )); |
110 | |
111 | OTV_LIMIT_CHECK( BaseCoordCount * 2 ); |
112 | |
113 | /* BaseCoord */ |
114 | for ( ; BaseCoordCount > 0; BaseCoordCount-- ) |
115 | otv_BaseCoord_validate( table + FT_NEXT_USHORT( p ), otvalid ); |
116 | |
117 | OTV_EXIT; |
118 | } |
119 | |
120 | |
121 | static void |
122 | otv_MinMax_validate( FT_Bytes table, |
123 | OTV_Validator otvalid ) |
124 | { |
125 | FT_Bytes p = table; |
126 | FT_UInt table_size; |
127 | FT_UInt FeatMinMaxCount; |
128 | |
129 | OTV_OPTIONAL_TABLE( MinCoord ); |
130 | OTV_OPTIONAL_TABLE( MaxCoord ); |
131 | |
132 | |
133 | OTV_NAME_ENTER( "MinMax" ); |
134 | |
135 | OTV_LIMIT_CHECK( 6 ); |
136 | |
137 | OTV_OPTIONAL_OFFSET( MinCoord ); |
138 | OTV_OPTIONAL_OFFSET( MaxCoord ); |
139 | FeatMinMaxCount = FT_NEXT_USHORT( p ); |
140 | |
141 | OTV_TRACE(( " (FeatMinMaxCount = %d)\n" , FeatMinMaxCount )); |
142 | |
143 | table_size = FeatMinMaxCount * 8 + 6; |
144 | |
145 | OTV_SIZE_CHECK( MinCoord ); |
146 | if ( MinCoord ) |
147 | otv_BaseCoord_validate( table + MinCoord, otvalid ); |
148 | |
149 | OTV_SIZE_CHECK( MaxCoord ); |
150 | if ( MaxCoord ) |
151 | otv_BaseCoord_validate( table + MaxCoord, otvalid ); |
152 | |
153 | OTV_LIMIT_CHECK( FeatMinMaxCount * 8 ); |
154 | |
155 | /* FeatMinMaxRecord */ |
156 | for ( ; FeatMinMaxCount > 0; FeatMinMaxCount-- ) |
157 | { |
158 | p += 4; /* skip FeatureTableTag */ |
159 | |
160 | OTV_OPTIONAL_OFFSET( MinCoord ); |
161 | OTV_OPTIONAL_OFFSET( MaxCoord ); |
162 | |
163 | OTV_SIZE_CHECK( MinCoord ); |
164 | if ( MinCoord ) |
165 | otv_BaseCoord_validate( table + MinCoord, otvalid ); |
166 | |
167 | OTV_SIZE_CHECK( MaxCoord ); |
168 | if ( MaxCoord ) |
169 | otv_BaseCoord_validate( table + MaxCoord, otvalid ); |
170 | } |
171 | |
172 | OTV_EXIT; |
173 | } |
174 | |
175 | |
176 | static void |
177 | otv_BaseScript_validate( FT_Bytes table, |
178 | OTV_Validator otvalid ) |
179 | { |
180 | FT_Bytes p = table; |
181 | FT_UInt table_size; |
182 | FT_UInt BaseLangSysCount; |
183 | |
184 | OTV_OPTIONAL_TABLE( BaseValues ); |
185 | OTV_OPTIONAL_TABLE( DefaultMinMax ); |
186 | |
187 | |
188 | OTV_NAME_ENTER( "BaseScript" ); |
189 | |
190 | OTV_LIMIT_CHECK( 6 ); |
191 | OTV_OPTIONAL_OFFSET( BaseValues ); |
192 | OTV_OPTIONAL_OFFSET( DefaultMinMax ); |
193 | BaseLangSysCount = FT_NEXT_USHORT( p ); |
194 | |
195 | OTV_TRACE(( " (BaseLangSysCount = %d)\n" , BaseLangSysCount )); |
196 | |
197 | table_size = BaseLangSysCount * 6 + 6; |
198 | |
199 | OTV_SIZE_CHECK( BaseValues ); |
200 | if ( BaseValues ) |
201 | otv_BaseValues_validate( table + BaseValues, otvalid ); |
202 | |
203 | OTV_SIZE_CHECK( DefaultMinMax ); |
204 | if ( DefaultMinMax ) |
205 | otv_MinMax_validate( table + DefaultMinMax, otvalid ); |
206 | |
207 | OTV_LIMIT_CHECK( BaseLangSysCount * 6 ); |
208 | |
209 | /* BaseLangSysRecord */ |
210 | for ( ; BaseLangSysCount > 0; BaseLangSysCount-- ) |
211 | { |
212 | p += 4; /* skip BaseLangSysTag */ |
213 | |
214 | otv_MinMax_validate( table + FT_NEXT_USHORT( p ), otvalid ); |
215 | } |
216 | |
217 | OTV_EXIT; |
218 | } |
219 | |
220 | |
221 | static void |
222 | otv_BaseScriptList_validate( FT_Bytes table, |
223 | OTV_Validator otvalid ) |
224 | { |
225 | FT_Bytes p = table; |
226 | FT_UInt BaseScriptCount; |
227 | |
228 | |
229 | OTV_NAME_ENTER( "BaseScriptList" ); |
230 | |
231 | OTV_LIMIT_CHECK( 2 ); |
232 | BaseScriptCount = FT_NEXT_USHORT( p ); |
233 | |
234 | OTV_TRACE(( " (BaseScriptCount = %d)\n" , BaseScriptCount )); |
235 | |
236 | OTV_LIMIT_CHECK( BaseScriptCount * 6 ); |
237 | |
238 | /* BaseScriptRecord */ |
239 | for ( ; BaseScriptCount > 0; BaseScriptCount-- ) |
240 | { |
241 | p += 4; /* skip BaseScriptTag */ |
242 | |
243 | /* BaseScript */ |
244 | otv_BaseScript_validate( table + FT_NEXT_USHORT( p ), otvalid ); |
245 | } |
246 | |
247 | OTV_EXIT; |
248 | } |
249 | |
250 | |
251 | static void |
252 | otv_Axis_validate( FT_Bytes table, |
253 | OTV_Validator otvalid ) |
254 | { |
255 | FT_Bytes p = table; |
256 | FT_UInt table_size; |
257 | |
258 | OTV_OPTIONAL_TABLE( BaseTagList ); |
259 | |
260 | |
261 | OTV_NAME_ENTER( "Axis" ); |
262 | |
263 | OTV_LIMIT_CHECK( 4 ); |
264 | OTV_OPTIONAL_OFFSET( BaseTagList ); |
265 | |
266 | table_size = 4; |
267 | |
268 | OTV_SIZE_CHECK( BaseTagList ); |
269 | if ( BaseTagList ) |
270 | otv_BaseTagList_validate( table + BaseTagList, otvalid ); |
271 | |
272 | /* BaseScriptList */ |
273 | otv_BaseScriptList_validate( table + FT_NEXT_USHORT( p ), otvalid ); |
274 | |
275 | OTV_EXIT; |
276 | } |
277 | |
278 | |
279 | FT_LOCAL_DEF( void ) |
280 | otv_BASE_validate( FT_Bytes table, |
281 | FT_Validator ftvalid ) |
282 | { |
283 | OTV_ValidatorRec otvalidrec; |
284 | OTV_Validator otvalid = &otvalidrec; |
285 | FT_Bytes p = table; |
286 | FT_UInt table_size; |
287 | FT_UShort version; |
288 | |
289 | OTV_OPTIONAL_TABLE( HorizAxis ); |
290 | OTV_OPTIONAL_TABLE( VertAxis ); |
291 | |
292 | OTV_OPTIONAL_TABLE32( itemVarStore ); |
293 | |
294 | |
295 | otvalid->root = ftvalid; |
296 | |
297 | FT_TRACE3(( "validating BASE table\n" )); |
298 | OTV_INIT; |
299 | |
300 | OTV_LIMIT_CHECK( 4 ); |
301 | |
302 | if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */ |
303 | FT_INVALID_FORMAT; |
304 | |
305 | version = FT_NEXT_USHORT( p ); /* minorVersion */ |
306 | |
307 | table_size = 8; |
308 | switch ( version ) |
309 | { |
310 | case 0: |
311 | OTV_LIMIT_CHECK( 4 ); |
312 | break; |
313 | |
314 | case 1: |
315 | OTV_LIMIT_CHECK( 8 ); |
316 | table_size += 4; |
317 | break; |
318 | |
319 | default: |
320 | FT_INVALID_FORMAT; |
321 | } |
322 | |
323 | OTV_OPTIONAL_OFFSET( HorizAxis ); |
324 | OTV_SIZE_CHECK( HorizAxis ); |
325 | if ( HorizAxis ) |
326 | otv_Axis_validate( table + HorizAxis, otvalid ); |
327 | |
328 | OTV_OPTIONAL_OFFSET( VertAxis ); |
329 | OTV_SIZE_CHECK( VertAxis ); |
330 | if ( VertAxis ) |
331 | otv_Axis_validate( table + VertAxis, otvalid ); |
332 | |
333 | if ( version > 0 ) |
334 | { |
335 | OTV_OPTIONAL_OFFSET32( itemVarStore ); |
336 | OTV_SIZE_CHECK32( itemVarStore ); |
337 | if ( itemVarStore ) |
338 | OTV_TRACE(( " [omitting itemVarStore validation]\n" )); /* XXX */ |
339 | } |
340 | |
341 | FT_TRACE4(( "\n" )); |
342 | } |
343 | |
344 | |
345 | /* END */ |
346 | |