1/****************************************************************************
2 *
3 * otvgsub.c
4 *
5 * OpenType GSUB 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 otvgsub
31
32
33 /*************************************************************************/
34 /*************************************************************************/
35 /***** *****/
36 /***** GSUB LOOKUP TYPE 1 *****/
37 /***** *****/
38 /*************************************************************************/
39 /*************************************************************************/
40
41 /* uses otvalid->glyph_count */
42
43 static void
44 otv_SingleSubst_validate( FT_Bytes table,
45 OTV_Validator otvalid )
46 {
47 FT_Bytes p = table;
48 FT_UInt SubstFormat;
49
50
51 OTV_NAME_ENTER( "SingleSubst" );
52
53 OTV_LIMIT_CHECK( 2 );
54 SubstFormat = FT_NEXT_USHORT( p );
55
56 OTV_TRACE(( " (format %d)\n", SubstFormat ));
57
58 switch ( SubstFormat )
59 {
60 case 1: /* SingleSubstFormat1 */
61 {
62 FT_Bytes Coverage;
63 FT_Int DeltaGlyphID;
64 FT_UInt first_cov, last_cov;
65 FT_UInt first_idx, last_idx;
66
67
68 OTV_LIMIT_CHECK( 4 );
69 Coverage = table + FT_NEXT_USHORT( p );
70 DeltaGlyphID = FT_NEXT_SHORT( p );
71
72 otv_Coverage_validate( Coverage, otvalid, -1 );
73
74 first_cov = otv_Coverage_get_first( Coverage );
75 last_cov = otv_Coverage_get_last( Coverage );
76
77 /* These additions are modulo 65536. */
78 first_idx = (FT_UInt)( (FT_Int)first_cov + DeltaGlyphID ) & 0xFFFFU;
79 last_idx = (FT_UInt)( (FT_Int)last_cov + DeltaGlyphID ) & 0xFFFFU;
80
81 /* Since the maximum number of glyphs is 2^16 - 1 = 65535, */
82 /* the largest possible glyph index is 65534. For this */
83 /* reason there can't be a wrap-around region, which would */
84 /* imply the use of the invalid glyph index 65535. */
85 if ( first_idx > last_idx )
86 FT_INVALID_DATA;
87
88 if ( last_idx >= otvalid->glyph_count )
89 FT_INVALID_DATA;
90 }
91 break;
92
93 case 2: /* SingleSubstFormat2 */
94 {
95 FT_UInt Coverage, GlyphCount;
96
97
98 OTV_LIMIT_CHECK( 4 );
99 Coverage = FT_NEXT_USHORT( p );
100 GlyphCount = FT_NEXT_USHORT( p );
101
102 OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
103
104 otv_Coverage_validate( table + Coverage,
105 otvalid,
106 (FT_Int)GlyphCount );
107
108 OTV_LIMIT_CHECK( GlyphCount * 2 );
109
110 /* Substitute */
111 for ( ; GlyphCount > 0; GlyphCount-- )
112 if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
113 FT_INVALID_GLYPH_ID;
114 }
115 break;
116
117 default:
118 FT_INVALID_FORMAT;
119 }
120
121 OTV_EXIT;
122 }
123
124
125 /*************************************************************************/
126 /*************************************************************************/
127 /***** *****/
128 /***** GSUB LOOKUP TYPE 2 *****/
129 /***** *****/
130 /*************************************************************************/
131 /*************************************************************************/
132
133 /* sets otvalid->extra1 (glyph count) */
134
135 static void
136 otv_MultipleSubst_validate( FT_Bytes table,
137 OTV_Validator otvalid )
138 {
139 FT_Bytes p = table;
140 FT_UInt SubstFormat;
141
142
143 OTV_NAME_ENTER( "MultipleSubst" );
144
145 OTV_LIMIT_CHECK( 2 );
146 SubstFormat = FT_NEXT_USHORT( p );
147
148 OTV_TRACE(( " (format %d)\n", SubstFormat ));
149
150 switch ( SubstFormat )
151 {
152 case 1:
153 otvalid->extra1 = otvalid->glyph_count;
154 OTV_NEST2( MultipleSubstFormat1, Sequence );
155 OTV_RUN( table, otvalid );
156 break;
157
158 default:
159 FT_INVALID_FORMAT;
160 }
161
162 OTV_EXIT;
163 }
164
165
166 /*************************************************************************/
167 /*************************************************************************/
168 /***** *****/
169 /***** GSUB LOOKUP TYPE 3 *****/
170 /***** *****/
171 /*************************************************************************/
172 /*************************************************************************/
173
174 /* sets otvalid->extra1 (glyph count) */
175
176 static void
177 otv_AlternateSubst_validate( FT_Bytes table,
178 OTV_Validator otvalid )
179 {
180 FT_Bytes p = table;
181 FT_UInt SubstFormat;
182
183
184 OTV_NAME_ENTER( "AlternateSubst" );
185
186 OTV_LIMIT_CHECK( 2 );
187 SubstFormat = FT_NEXT_USHORT( p );
188
189 OTV_TRACE(( " (format %d)\n", SubstFormat ));
190
191 switch ( SubstFormat )
192 {
193 case 1:
194 otvalid->extra1 = otvalid->glyph_count;
195 OTV_NEST2( AlternateSubstFormat1, AlternateSet );
196 OTV_RUN( table, otvalid );
197 break;
198
199 default:
200 FT_INVALID_FORMAT;
201 }
202
203 OTV_EXIT;
204 }
205
206
207 /*************************************************************************/
208 /*************************************************************************/
209 /***** *****/
210 /***** GSUB LOOKUP TYPE 4 *****/
211 /***** *****/
212 /*************************************************************************/
213 /*************************************************************************/
214
215#define LigatureFunc otv_Ligature_validate
216
217 /* uses otvalid->glyph_count */
218
219 static void
220 otv_Ligature_validate( FT_Bytes table,
221 OTV_Validator otvalid )
222 {
223 FT_Bytes p = table;
224 FT_UInt LigatureGlyph, CompCount;
225
226
227 OTV_ENTER;
228
229 OTV_LIMIT_CHECK( 4 );
230 LigatureGlyph = FT_NEXT_USHORT( p );
231 if ( LigatureGlyph >= otvalid->glyph_count )
232 FT_INVALID_DATA;
233
234 CompCount = FT_NEXT_USHORT( p );
235
236 OTV_TRACE(( " (CompCount = %d)\n", CompCount ));
237
238 if ( CompCount == 0 )
239 FT_INVALID_DATA;
240
241 CompCount--;
242
243 OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */
244
245 /* no need to check the Component glyph indices */
246
247 OTV_EXIT;
248 }
249
250
251 static void
252 otv_LigatureSubst_validate( FT_Bytes table,
253 OTV_Validator otvalid )
254 {
255 FT_Bytes p = table;
256 FT_UInt SubstFormat;
257
258
259 OTV_NAME_ENTER( "LigatureSubst" );
260
261 OTV_LIMIT_CHECK( 2 );
262 SubstFormat = FT_NEXT_USHORT( p );
263
264 OTV_TRACE(( " (format %d)\n", SubstFormat ));
265
266 switch ( SubstFormat )
267 {
268 case 1:
269 OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature );
270 OTV_RUN( table, otvalid );
271 break;
272
273 default:
274 FT_INVALID_FORMAT;
275 }
276
277 OTV_EXIT;
278 }
279
280
281 /*************************************************************************/
282 /*************************************************************************/
283 /***** *****/
284 /***** GSUB LOOKUP TYPE 5 *****/
285 /***** *****/
286 /*************************************************************************/
287 /*************************************************************************/
288
289 /* sets otvalid->extra1 (lookup count) */
290
291 static void
292 otv_ContextSubst_validate( FT_Bytes table,
293 OTV_Validator otvalid )
294 {
295 FT_Bytes p = table;
296 FT_UInt SubstFormat;
297
298
299 OTV_NAME_ENTER( "ContextSubst" );
300
301 OTV_LIMIT_CHECK( 2 );
302 SubstFormat = FT_NEXT_USHORT( p );
303
304 OTV_TRACE(( " (format %d)\n", SubstFormat ));
305
306 switch ( SubstFormat )
307 {
308 case 1:
309 /* no need to check glyph indices/classes used as input for these */
310 /* context rules since even invalid glyph indices/classes return */
311 /* meaningful results */
312
313 otvalid->extra1 = otvalid->lookup_count;
314 OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule );
315 OTV_RUN( table, otvalid );
316 break;
317
318 case 2:
319 /* no need to check glyph indices/classes used as input for these */
320 /* context rules since even invalid glyph indices/classes return */
321 /* meaningful results */
322
323 OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule );
324 OTV_RUN( table, otvalid );
325 break;
326
327 case 3:
328 OTV_NEST1( ContextSubstFormat3 );
329 OTV_RUN( table, otvalid );
330 break;
331
332 default:
333 FT_INVALID_FORMAT;
334 }
335
336 OTV_EXIT;
337 }
338
339
340 /*************************************************************************/
341 /*************************************************************************/
342 /***** *****/
343 /***** GSUB LOOKUP TYPE 6 *****/
344 /***** *****/
345 /*************************************************************************/
346 /*************************************************************************/
347
348 /* sets otvalid->extra1 (lookup count) */
349
350 static void
351 otv_ChainContextSubst_validate( FT_Bytes table,
352 OTV_Validator otvalid )
353 {
354 FT_Bytes p = table;
355 FT_UInt SubstFormat;
356
357
358 OTV_NAME_ENTER( "ChainContextSubst" );
359
360 OTV_LIMIT_CHECK( 2 );
361 SubstFormat = FT_NEXT_USHORT( p );
362
363 OTV_TRACE(( " (format %d)\n", SubstFormat ));
364
365 switch ( SubstFormat )
366 {
367 case 1:
368 /* no need to check glyph indices/classes used as input for these */
369 /* context rules since even invalid glyph indices/classes return */
370 /* meaningful results */
371
372 otvalid->extra1 = otvalid->lookup_count;
373 OTV_NEST3( ChainContextSubstFormat1,
374 ChainSubRuleSet, ChainSubRule );
375 OTV_RUN( table, otvalid );
376 break;
377
378 case 2:
379 /* no need to check glyph indices/classes used as input for these */
380 /* context rules since even invalid glyph indices/classes return */
381 /* meaningful results */
382
383 OTV_NEST3( ChainContextSubstFormat2,
384 ChainSubClassSet, ChainSubClassRule );
385 OTV_RUN( table, otvalid );
386 break;
387
388 case 3:
389 OTV_NEST1( ChainContextSubstFormat3 );
390 OTV_RUN( table, otvalid );
391 break;
392
393 default:
394 FT_INVALID_FORMAT;
395 }
396
397 OTV_EXIT;
398 }
399
400
401 /*************************************************************************/
402 /*************************************************************************/
403 /***** *****/
404 /***** GSUB LOOKUP TYPE 7 *****/
405 /***** *****/
406 /*************************************************************************/
407 /*************************************************************************/
408
409 /* uses otvalid->type_funcs */
410
411 static void
412 otv_ExtensionSubst_validate( FT_Bytes table,
413 OTV_Validator otvalid )
414 {
415 FT_Bytes p = table;
416 FT_UInt SubstFormat;
417
418
419 OTV_NAME_ENTER( "ExtensionSubst" );
420
421 OTV_LIMIT_CHECK( 2 );
422 SubstFormat = FT_NEXT_USHORT( p );
423
424 OTV_TRACE(( " (format %d)\n", SubstFormat ));
425
426 switch ( SubstFormat )
427 {
428 case 1: /* ExtensionSubstFormat1 */
429 {
430 FT_UInt ExtensionLookupType;
431 FT_ULong ExtensionOffset;
432 OTV_Validate_Func validate;
433
434
435 OTV_LIMIT_CHECK( 6 );
436 ExtensionLookupType = FT_NEXT_USHORT( p );
437 ExtensionOffset = FT_NEXT_ULONG( p );
438
439 if ( ExtensionLookupType == 0 ||
440 ExtensionLookupType == 7 ||
441 ExtensionLookupType > 8 )
442 FT_INVALID_DATA;
443
444 validate = otvalid->type_funcs[ExtensionLookupType - 1];
445 validate( table + ExtensionOffset, otvalid );
446 }
447 break;
448
449 default:
450 FT_INVALID_FORMAT;
451 }
452
453 OTV_EXIT;
454 }
455
456
457 /*************************************************************************/
458 /*************************************************************************/
459 /***** *****/
460 /***** GSUB LOOKUP TYPE 8 *****/
461 /***** *****/
462 /*************************************************************************/
463 /*************************************************************************/
464
465 /* uses otvalid->glyph_count */
466
467 static void
468 otv_ReverseChainSingleSubst_validate( FT_Bytes table,
469 OTV_Validator otvalid )
470 {
471 FT_Bytes p = table, Coverage;
472 FT_UInt SubstFormat;
473 FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount;
474
475
476 OTV_NAME_ENTER( "ReverseChainSingleSubst" );
477
478 OTV_LIMIT_CHECK( 2 );
479 SubstFormat = FT_NEXT_USHORT( p );
480
481 OTV_TRACE(( " (format %d)\n", SubstFormat ));
482
483 switch ( SubstFormat )
484 {
485 case 1: /* ReverseChainSingleSubstFormat1 */
486 OTV_LIMIT_CHECK( 4 );
487 Coverage = table + FT_NEXT_USHORT( p );
488 BacktrackGlyphCount = FT_NEXT_USHORT( p );
489
490 OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount ));
491
492 otv_Coverage_validate( Coverage, otvalid, -1 );
493
494 OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 );
495
496 for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- )
497 otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
498
499 LookaheadGlyphCount = FT_NEXT_USHORT( p );
500
501 OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount ));
502
503 OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 );
504
505 for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- )
506 otv_Coverage_validate( table + FT_NEXT_USHORT( p ), otvalid, -1 );
507
508 GlyphCount = FT_NEXT_USHORT( p );
509
510 OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount ));
511
512 if ( GlyphCount != otv_Coverage_get_count( Coverage ) )
513 FT_INVALID_DATA;
514
515 OTV_LIMIT_CHECK( GlyphCount * 2 );
516
517 /* Substitute */
518 for ( ; GlyphCount > 0; GlyphCount-- )
519 if ( FT_NEXT_USHORT( p ) >= otvalid->glyph_count )
520 FT_INVALID_DATA;
521
522 break;
523
524 default:
525 FT_INVALID_FORMAT;
526 }
527
528 OTV_EXIT;
529 }
530
531
532 static const OTV_Validate_Func otv_gsub_validate_funcs[8] =
533 {
534 otv_SingleSubst_validate,
535 otv_MultipleSubst_validate,
536 otv_AlternateSubst_validate,
537 otv_LigatureSubst_validate,
538 otv_ContextSubst_validate,
539 otv_ChainContextSubst_validate,
540 otv_ExtensionSubst_validate,
541 otv_ReverseChainSingleSubst_validate
542 };
543
544
545 /*************************************************************************/
546 /*************************************************************************/
547 /***** *****/
548 /***** GSUB TABLE *****/
549 /***** *****/
550 /*************************************************************************/
551 /*************************************************************************/
552
553 /* sets otvalid->type_count */
554 /* sets otvalid->type_funcs */
555 /* sets otvalid->glyph_count */
556
557 FT_LOCAL_DEF( void )
558 otv_GSUB_validate( FT_Bytes table,
559 FT_UInt glyph_count,
560 FT_Validator ftvalid )
561 {
562 OTV_ValidatorRec otvalidrec;
563 OTV_Validator otvalid = &otvalidrec;
564 FT_Bytes p = table;
565 FT_UInt table_size;
566 FT_UShort version;
567 FT_UInt ScriptList, FeatureList, LookupList;
568
569 OTV_OPTIONAL_TABLE32( featureVariations );
570
571
572 otvalid->root = ftvalid;
573
574 FT_TRACE3(( "validating GSUB table\n" ));
575 OTV_INIT;
576
577 OTV_LIMIT_CHECK( 4 );
578
579 if ( FT_NEXT_USHORT( p ) != 1 ) /* majorVersion */
580 FT_INVALID_FORMAT;
581
582 version = FT_NEXT_USHORT( p ); /* minorVersion */
583
584 table_size = 10;
585 switch ( version )
586 {
587 case 0:
588 OTV_LIMIT_CHECK( 6 );
589 break;
590
591 case 1:
592 OTV_LIMIT_CHECK( 10 );
593 table_size += 4;
594 break;
595
596 default:
597 FT_INVALID_FORMAT;
598 }
599
600 ScriptList = FT_NEXT_USHORT( p );
601 FeatureList = FT_NEXT_USHORT( p );
602 LookupList = FT_NEXT_USHORT( p );
603
604 otvalid->type_count = 8;
605 otvalid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs;
606 otvalid->glyph_count = glyph_count;
607
608 otv_LookupList_validate( table + LookupList,
609 otvalid );
610 otv_FeatureList_validate( table + FeatureList, table + LookupList,
611 otvalid );
612 otv_ScriptList_validate( table + ScriptList, table + FeatureList,
613 otvalid );
614
615 if ( version > 0 )
616 {
617 OTV_OPTIONAL_OFFSET32( featureVariations );
618 OTV_SIZE_CHECK32( featureVariations );
619 if ( featureVariations )
620 OTV_TRACE(( " [omitting featureVariations validation]\n" )); /* XXX */
621 }
622
623 FT_TRACE4(( "\n" ));
624 }
625
626
627/* END */
628