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