Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / src / otvalid / otvgsub.c
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 */