otvgpos.c revision 6d403d089d438f3a3f9a13c47e2c93528819f265
1/***************************************************************************/
2/*                                                                         */
3/*  otvgpos.c                                                              */
4/*                                                                         */
5/*    OpenType GPOS table validation (body).                               */
6/*                                                                         */
7/*  Copyright 2002-2017 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  trace_otvgpos
32
33
34  static void
35  otv_Anchor_validate( FT_Bytes       table,
36                       OTV_Validator  valid );
37
38  static void
39  otv_MarkArray_validate( FT_Bytes       table,
40                          OTV_Validator  valid );
41
42
43  /*************************************************************************/
44  /*************************************************************************/
45  /*****                                                               *****/
46  /*****                      UTILITY FUNCTIONS                        *****/
47  /*****                                                               *****/
48  /*************************************************************************/
49  /*************************************************************************/
50
51#define BaseArrayFunc       otv_x_sxy
52#define LigatureAttachFunc  otv_x_sxy
53#define Mark2ArrayFunc      otv_x_sxy
54
55  /* uses valid->extra1 (counter)                             */
56  /* uses valid->extra2 (boolean to handle NULL anchor field) */
57
58  static void
59  otv_x_sxy( FT_Bytes       table,
60             OTV_Validator  otvalid )
61  {
62    FT_Bytes  p = table;
63    FT_UInt   Count, count1, table_size;
64
65
66    OTV_ENTER;
67
68    OTV_LIMIT_CHECK( 2 );
69
70    Count = FT_NEXT_USHORT( p );
71
72    OTV_TRACE(( " (Count = %d)\n", Count ));
73
74    OTV_LIMIT_CHECK( Count * otvalid->extra1 * 2 );
75
76    table_size = Count * otvalid->extra1 * 2 + 2;
77
78    for ( ; Count > 0; Count-- )
79      for ( count1 = otvalid->extra1; count1 > 0; count1-- )
80      {
81        OTV_OPTIONAL_TABLE( anchor_offset );
82
83
84        OTV_OPTIONAL_OFFSET( anchor_offset );
85
86        if ( otvalid->extra2 )
87        {
88          OTV_SIZE_CHECK( anchor_offset );
89          if ( anchor_offset )
90            otv_Anchor_validate( table + anchor_offset, otvalid );
91        }
92        else
93          otv_Anchor_validate( table + anchor_offset, otvalid );
94      }
95
96    OTV_EXIT;
97  }
98
99
100#define MarkBasePosFormat1Func  otv_u_O_O_u_O_O
101#define MarkLigPosFormat1Func   otv_u_O_O_u_O_O
102#define MarkMarkPosFormat1Func  otv_u_O_O_u_O_O
103
104  /* sets otvalid->extra1 (class count) */
105
106  static void
107  otv_u_O_O_u_O_O( FT_Bytes       table,
108                   OTV_Validator  otvalid )
109  {
110    FT_Bytes           p = table;
111    FT_UInt            Coverage1, Coverage2, ClassCount;
112    FT_UInt            Array1, Array2;
113    OTV_Validate_Func  func;
114
115
116    OTV_ENTER;
117
118    p += 2;     /* skip PosFormat */
119
120    OTV_LIMIT_CHECK( 10 );
121    Coverage1  = FT_NEXT_USHORT( p );
122    Coverage2  = FT_NEXT_USHORT( p );
123    ClassCount = FT_NEXT_USHORT( p );
124    Array1     = FT_NEXT_USHORT( p );
125    Array2     = FT_NEXT_USHORT( p );
126
127    otv_Coverage_validate( table + Coverage1, otvalid, -1 );
128    otv_Coverage_validate( table + Coverage2, otvalid, -1 );
129
130    otv_MarkArray_validate( table + Array1, otvalid );
131
132    otvalid->nesting_level++;
133    func            = otvalid->func[otvalid->nesting_level];
134    otvalid->extra1 = ClassCount;
135
136    func( table + Array2, otvalid );
137
138    otvalid->nesting_level--;
139
140    OTV_EXIT;
141  }
142
143
144  /*************************************************************************/
145  /*************************************************************************/
146  /*****                                                               *****/
147  /*****                        VALUE RECORDS                          *****/
148  /*****                                                               *****/
149  /*************************************************************************/
150  /*************************************************************************/
151
152  static FT_UInt
153  otv_value_length( FT_UInt  format )
154  {
155    FT_UInt  count;
156
157
158    count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 );
159    count = ( ( count  & 0xCC ) >> 2 ) + ( count  & 0x33 );
160    count = ( ( count  & 0xF0 ) >> 4 ) + ( count  & 0x0F );
161
162    return count * 2;
163  }
164
165
166  /* uses otvalid->extra3 (pointer to base table) */
167
168  static void
169  otv_ValueRecord_validate( FT_Bytes       table,
170                            FT_UInt        format,
171                            OTV_Validator  otvalid )
172  {
173    FT_Bytes  p = table;
174    FT_UInt   count;
175
176#ifdef FT_DEBUG_LEVEL_TRACE
177    FT_Int    loop;
178    FT_ULong  res = 0;
179
180
181    OTV_NAME_ENTER( "ValueRecord" );
182
183    /* display `format' in dual representation */
184    for ( loop = 7; loop >= 0; loop-- )
185    {
186      res <<= 4;
187      res  += ( format >> loop ) & 1;
188    }
189
190    OTV_TRACE(( " (format 0b%08lx)\n", res ));
191#endif
192
193    if ( format >= 0x100 )
194      FT_INVALID_FORMAT;
195
196    for ( count = 4; count > 0; count-- )
197    {
198      if ( format & 1 )
199      {
200        /* XPlacement, YPlacement, XAdvance, YAdvance */
201        OTV_LIMIT_CHECK( 2 );
202        p += 2;
203      }
204
205      format >>= 1;
206    }
207
208    for ( count = 4; count > 0; count-- )
209    {
210      if ( format & 1 )
211      {
212        FT_PtrDist  table_size;
213
214        OTV_OPTIONAL_TABLE( device );
215
216
217        /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */
218        OTV_LIMIT_CHECK( 2 );
219        OTV_OPTIONAL_OFFSET( device );
220
221        table_size = p - otvalid->extra3;
222
223        OTV_SIZE_CHECK( device );
224        if ( device )
225          otv_Device_validate( otvalid->extra3 + device, otvalid );
226      }
227      format >>= 1;
228    }
229
230    OTV_EXIT;
231  }
232
233
234  /*************************************************************************/
235  /*************************************************************************/
236  /*****                                                               *****/
237  /*****                           ANCHORS                             *****/
238  /*****                                                               *****/
239  /*************************************************************************/
240  /*************************************************************************/
241
242  static void
243  otv_Anchor_validate( FT_Bytes       table,
244                       OTV_Validator  otvalid )
245  {
246    FT_Bytes  p = table;
247    FT_UInt   AnchorFormat;
248
249
250    OTV_NAME_ENTER( "Anchor");
251
252    OTV_LIMIT_CHECK( 6 );
253    AnchorFormat = FT_NEXT_USHORT( p );
254
255    OTV_TRACE(( " (format %d)\n", AnchorFormat ));
256
257    p += 4;     /* skip XCoordinate and YCoordinate */
258
259    switch ( AnchorFormat )
260    {
261    case 1:
262      break;
263
264    case 2:
265      OTV_LIMIT_CHECK( 2 );  /* AnchorPoint */
266      break;
267
268    case 3:
269      {
270        FT_UInt  table_size;
271
272        OTV_OPTIONAL_TABLE( XDeviceTable );
273        OTV_OPTIONAL_TABLE( YDeviceTable );
274
275
276        OTV_LIMIT_CHECK( 4 );
277        OTV_OPTIONAL_OFFSET( XDeviceTable );
278        OTV_OPTIONAL_OFFSET( YDeviceTable );
279
280        table_size = 6 + 4;
281
282        OTV_SIZE_CHECK( XDeviceTable );
283        if ( XDeviceTable )
284          otv_Device_validate( table + XDeviceTable, otvalid );
285
286        OTV_SIZE_CHECK( YDeviceTable );
287        if ( YDeviceTable )
288          otv_Device_validate( table + YDeviceTable, otvalid );
289      }
290      break;
291
292    default:
293      FT_INVALID_FORMAT;
294    }
295
296    OTV_EXIT;
297  }
298
299
300  /*************************************************************************/
301  /*************************************************************************/
302  /*****                                                               *****/
303  /*****                         MARK ARRAYS                           *****/
304  /*****                                                               *****/
305  /*************************************************************************/
306  /*************************************************************************/
307
308  static void
309  otv_MarkArray_validate( FT_Bytes       table,
310                          OTV_Validator  otvalid )
311  {
312    FT_Bytes  p = table;
313    FT_UInt   MarkCount;
314
315
316    OTV_NAME_ENTER( "MarkArray" );
317
318    OTV_LIMIT_CHECK( 2 );
319    MarkCount = FT_NEXT_USHORT( p );
320
321    OTV_TRACE(( " (MarkCount = %d)\n", MarkCount ));
322
323    OTV_LIMIT_CHECK( MarkCount * 4 );
324
325    /* MarkRecord */
326    for ( ; MarkCount > 0; MarkCount-- )
327    {
328      p += 2;   /* skip Class */
329      /* MarkAnchor */
330      otv_Anchor_validate( table + FT_NEXT_USHORT( p ), otvalid );
331    }
332
333    OTV_EXIT;
334  }
335
336
337  /*************************************************************************/
338  /*************************************************************************/
339  /*****                                                               *****/
340  /*****                     GPOS LOOKUP TYPE 1                        *****/
341  /*****                                                               *****/
342  /*************************************************************************/
343  /*************************************************************************/
344
345  /* sets otvalid->extra3 (pointer to base table) */
346
347  static void
348  otv_SinglePos_validate( FT_Bytes       table,
349                          OTV_Validator  otvalid )
350  {
351    FT_Bytes  p = table;
352    FT_UInt   PosFormat;
353
354
355    OTV_NAME_ENTER( "SinglePos" );
356
357    OTV_LIMIT_CHECK( 2 );
358    PosFormat = FT_NEXT_USHORT( p );
359
360    OTV_TRACE(( " (format %d)\n", PosFormat ));
361
362    otvalid->extra3 = table;
363
364    switch ( PosFormat )
365    {
366    case 1:     /* SinglePosFormat1 */
367      {
368        FT_UInt  Coverage, ValueFormat;
369
370
371        OTV_LIMIT_CHECK( 4 );
372        Coverage    = FT_NEXT_USHORT( p );
373        ValueFormat = FT_NEXT_USHORT( p );
374
375        otv_Coverage_validate( table + Coverage, otvalid, -1 );
376        otv_ValueRecord_validate( p, ValueFormat, otvalid ); /* Value */
377      }
378      break;
379
380    case 2:     /* SinglePosFormat2 */
381      {
382        FT_UInt  Coverage, ValueFormat, ValueCount, len_value;
383
384
385        OTV_LIMIT_CHECK( 6 );
386        Coverage    = FT_NEXT_USHORT( p );
387        ValueFormat = FT_NEXT_USHORT( p );
388        ValueCount  = FT_NEXT_USHORT( p );
389
390        OTV_TRACE(( " (ValueCount = %d)\n", ValueCount ));
391
392        len_value = otv_value_length( ValueFormat );
393
394        otv_Coverage_validate( table + Coverage,
395                               otvalid,
396                               (FT_Int)ValueCount );
397
398        OTV_LIMIT_CHECK( ValueCount * len_value );
399
400        /* Value */
401        for ( ; ValueCount > 0; ValueCount-- )
402        {
403          otv_ValueRecord_validate( p, ValueFormat, otvalid );
404          p += len_value;
405        }
406      }
407      break;
408
409    default:
410      FT_INVALID_FORMAT;
411    }
412
413    OTV_EXIT;
414  }
415
416
417  /*************************************************************************/
418  /*************************************************************************/
419  /*****                                                               *****/
420  /*****                     GPOS LOOKUP TYPE 2                        *****/
421  /*****                                                               *****/
422  /*************************************************************************/
423  /*************************************************************************/
424
425  /* sets otvalid->extra3 (pointer to base table) */
426
427  static void
428  otv_PairSet_validate( FT_Bytes       table,
429                        FT_UInt        format1,
430                        FT_UInt        format2,
431                        OTV_Validator  otvalid )
432  {
433    FT_Bytes  p = table;
434    FT_UInt   value_len1, value_len2, PairValueCount;
435
436
437    OTV_NAME_ENTER( "PairSet" );
438
439    otvalid->extra3 = table;
440
441    OTV_LIMIT_CHECK( 2 );
442    PairValueCount = FT_NEXT_USHORT( p );
443
444    OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount ));
445
446    value_len1 = otv_value_length( format1 );
447    value_len2 = otv_value_length( format2 );
448
449    OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) );
450
451    /* PairValueRecord */
452    for ( ; PairValueCount > 0; PairValueCount-- )
453    {
454      p += 2;       /* skip SecondGlyph */
455
456      if ( format1 )
457        otv_ValueRecord_validate( p, format1, otvalid ); /* Value1 */
458      p += value_len1;
459
460      if ( format2 )
461        otv_ValueRecord_validate( p, format2, otvalid ); /* Value2 */
462      p += value_len2;
463    }
464
465    OTV_EXIT;
466  }
467
468
469  /* sets otvalid->extra3 (pointer to base table) */
470
471  static void
472  otv_PairPos_validate( FT_Bytes       table,
473                        OTV_Validator  otvalid )
474  {
475    FT_Bytes  p = table;
476    FT_UInt   PosFormat;
477
478
479    OTV_NAME_ENTER( "PairPos" );
480
481    OTV_LIMIT_CHECK( 2 );
482    PosFormat = FT_NEXT_USHORT( p );
483
484    OTV_TRACE(( " (format %d)\n", PosFormat ));
485
486    switch ( PosFormat )
487    {
488    case 1:     /* PairPosFormat1 */
489      {
490        FT_UInt  Coverage, ValueFormat1, ValueFormat2, PairSetCount;
491
492
493        OTV_LIMIT_CHECK( 8 );
494        Coverage     = FT_NEXT_USHORT( p );
495        ValueFormat1 = FT_NEXT_USHORT( p );
496        ValueFormat2 = FT_NEXT_USHORT( p );
497        PairSetCount = FT_NEXT_USHORT( p );
498
499        OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount ));
500
501        otv_Coverage_validate( table + Coverage, otvalid, -1 );
502
503        OTV_LIMIT_CHECK( PairSetCount * 2 );
504
505        /* PairSetOffset */
506        for ( ; PairSetCount > 0; PairSetCount-- )
507          otv_PairSet_validate( table + FT_NEXT_USHORT( p ),
508                                ValueFormat1, ValueFormat2, otvalid );
509      }
510      break;
511
512    case 2:     /* PairPosFormat2 */
513      {
514        FT_UInt  Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2;
515        FT_UInt  ClassCount1, ClassCount2, len_value1, len_value2, count;
516
517
518        OTV_LIMIT_CHECK( 14 );
519        Coverage     = FT_NEXT_USHORT( p );
520        ValueFormat1 = FT_NEXT_USHORT( p );
521        ValueFormat2 = FT_NEXT_USHORT( p );
522        ClassDef1    = FT_NEXT_USHORT( p );
523        ClassDef2    = FT_NEXT_USHORT( p );
524        ClassCount1  = FT_NEXT_USHORT( p );
525        ClassCount2  = FT_NEXT_USHORT( p );
526
527        OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 ));
528        OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 ));
529
530        len_value1 = otv_value_length( ValueFormat1 );
531        len_value2 = otv_value_length( ValueFormat2 );
532
533        otv_Coverage_validate( table + Coverage, otvalid, -1 );
534        otv_ClassDef_validate( table + ClassDef1, otvalid );
535        otv_ClassDef_validate( table + ClassDef2, otvalid );
536
537        OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
538                         ( len_value1 + len_value2 ) );
539
540        otvalid->extra3 = table;
541
542        /* Class1Record */
543        for ( ; ClassCount1 > 0; ClassCount1-- )
544        {
545          /* Class2Record */
546          for ( count = ClassCount2; count > 0; count-- )
547          {
548            if ( ValueFormat1 )
549              /* Value1 */
550              otv_ValueRecord_validate( p, ValueFormat1, otvalid );
551            p += len_value1;
552
553            if ( ValueFormat2 )
554              /* Value2 */
555              otv_ValueRecord_validate( p, ValueFormat2, otvalid );
556            p += len_value2;
557          }
558        }
559      }
560      break;
561
562    default:
563      FT_INVALID_FORMAT;
564    }
565
566    OTV_EXIT;
567  }
568
569
570  /*************************************************************************/
571  /*************************************************************************/
572  /*****                                                               *****/
573  /*****                     GPOS LOOKUP TYPE 3                        *****/
574  /*****                                                               *****/
575  /*************************************************************************/
576  /*************************************************************************/
577
578  static void
579  otv_CursivePos_validate( FT_Bytes       table,
580                           OTV_Validator  otvalid )
581  {
582    FT_Bytes  p = table;
583    FT_UInt   PosFormat;
584
585
586    OTV_NAME_ENTER( "CursivePos" );
587
588    OTV_LIMIT_CHECK( 2 );
589    PosFormat = FT_NEXT_USHORT( p );
590
591    OTV_TRACE(( " (format %d)\n", PosFormat ));
592
593    switch ( PosFormat )
594    {
595    case 1:     /* CursivePosFormat1 */
596      {
597        FT_UInt   table_size;
598        FT_UInt   Coverage, EntryExitCount;
599
600        OTV_OPTIONAL_TABLE( EntryAnchor );
601        OTV_OPTIONAL_TABLE( ExitAnchor  );
602
603
604        OTV_LIMIT_CHECK( 4 );
605        Coverage       = FT_NEXT_USHORT( p );
606        EntryExitCount = FT_NEXT_USHORT( p );
607
608        OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
609
610        otv_Coverage_validate( table + Coverage,
611                               otvalid,
612                               (FT_Int)EntryExitCount );
613
614        OTV_LIMIT_CHECK( EntryExitCount * 4 );
615
616        table_size = EntryExitCount * 4 + 4;
617
618        /* EntryExitRecord */
619        for ( ; EntryExitCount > 0; EntryExitCount-- )
620        {
621          OTV_OPTIONAL_OFFSET( EntryAnchor );
622          OTV_OPTIONAL_OFFSET( ExitAnchor  );
623
624          OTV_SIZE_CHECK( EntryAnchor );
625          if ( EntryAnchor )
626            otv_Anchor_validate( table + EntryAnchor, otvalid );
627
628          OTV_SIZE_CHECK( ExitAnchor );
629          if ( ExitAnchor )
630            otv_Anchor_validate( table + ExitAnchor, otvalid );
631        }
632      }
633      break;
634
635    default:
636      FT_INVALID_FORMAT;
637    }
638
639    OTV_EXIT;
640  }
641
642
643  /*************************************************************************/
644  /*************************************************************************/
645  /*****                                                               *****/
646  /*****                     GPOS LOOKUP TYPE 4                        *****/
647  /*****                                                               *****/
648  /*************************************************************************/
649  /*************************************************************************/
650
651  /* UNDOCUMENTED (in OpenType 1.5):              */
652  /* BaseRecord tables can contain NULL pointers. */
653
654  /* sets otvalid->extra2 (1) */
655
656  static void
657  otv_MarkBasePos_validate( FT_Bytes       table,
658                            OTV_Validator  otvalid )
659  {
660    FT_Bytes  p = table;
661    FT_UInt   PosFormat;
662
663
664    OTV_NAME_ENTER( "MarkBasePos" );
665
666    OTV_LIMIT_CHECK( 2 );
667    PosFormat = FT_NEXT_USHORT( p );
668
669    OTV_TRACE(( " (format %d)\n", PosFormat ));
670
671    switch ( PosFormat )
672    {
673    case 1:
674      otvalid->extra2 = 1;
675      OTV_NEST2( MarkBasePosFormat1, BaseArray );
676      OTV_RUN( table, otvalid );
677      break;
678
679    default:
680      FT_INVALID_FORMAT;
681    }
682
683    OTV_EXIT;
684  }
685
686
687  /*************************************************************************/
688  /*************************************************************************/
689  /*****                                                               *****/
690  /*****                     GPOS LOOKUP TYPE 5                        *****/
691  /*****                                                               *****/
692  /*************************************************************************/
693  /*************************************************************************/
694
695  /* sets otvalid->extra2 (1) */
696
697  static void
698  otv_MarkLigPos_validate( FT_Bytes       table,
699                           OTV_Validator  otvalid )
700  {
701    FT_Bytes  p = table;
702    FT_UInt   PosFormat;
703
704
705    OTV_NAME_ENTER( "MarkLigPos" );
706
707    OTV_LIMIT_CHECK( 2 );
708    PosFormat = FT_NEXT_USHORT( p );
709
710    OTV_TRACE(( " (format %d)\n", PosFormat ));
711
712    switch ( PosFormat )
713    {
714    case 1:
715      otvalid->extra2 = 1;
716      OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
717      OTV_RUN( table, otvalid );
718      break;
719
720    default:
721      FT_INVALID_FORMAT;
722    }
723
724    OTV_EXIT;
725  }
726
727
728  /*************************************************************************/
729  /*************************************************************************/
730  /*****                                                               *****/
731  /*****                     GPOS LOOKUP TYPE 6                        *****/
732  /*****                                                               *****/
733  /*************************************************************************/
734  /*************************************************************************/
735
736  /* sets otvalid->extra2 (0) */
737
738  static void
739  otv_MarkMarkPos_validate( FT_Bytes       table,
740                            OTV_Validator  otvalid )
741  {
742    FT_Bytes  p = table;
743    FT_UInt   PosFormat;
744
745
746    OTV_NAME_ENTER( "MarkMarkPos" );
747
748    OTV_LIMIT_CHECK( 2 );
749    PosFormat = FT_NEXT_USHORT( p );
750
751    OTV_TRACE(( " (format %d)\n", PosFormat ));
752
753    switch ( PosFormat )
754    {
755    case 1:
756      otvalid->extra2 = 0;
757      OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
758      OTV_RUN( table, otvalid );
759      break;
760
761    default:
762      FT_INVALID_FORMAT;
763    }
764
765    OTV_EXIT;
766  }
767
768
769  /*************************************************************************/
770  /*************************************************************************/
771  /*****                                                               *****/
772  /*****                     GPOS LOOKUP TYPE 7                        *****/
773  /*****                                                               *****/
774  /*************************************************************************/
775  /*************************************************************************/
776
777  /* sets otvalid->extra1 (lookup count) */
778
779  static void
780  otv_ContextPos_validate( FT_Bytes       table,
781                           OTV_Validator  otvalid )
782  {
783    FT_Bytes  p = table;
784    FT_UInt   PosFormat;
785
786
787    OTV_NAME_ENTER( "ContextPos" );
788
789    OTV_LIMIT_CHECK( 2 );
790    PosFormat = FT_NEXT_USHORT( p );
791
792    OTV_TRACE(( " (format %d)\n", PosFormat ));
793
794    switch ( PosFormat )
795    {
796    case 1:
797      /* no need to check glyph indices/classes used as input for these */
798      /* context rules since even invalid glyph indices/classes return  */
799      /* meaningful results                                             */
800
801      otvalid->extra1 = otvalid->lookup_count;
802      OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
803      OTV_RUN( table, otvalid );
804      break;
805
806    case 2:
807      /* no need to check glyph indices/classes used as input for these */
808      /* context rules since even invalid glyph indices/classes return  */
809      /* meaningful results                                             */
810
811      OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
812      OTV_RUN( table, otvalid );
813      break;
814
815    case 3:
816      OTV_NEST1( ContextPosFormat3 );
817      OTV_RUN( table, otvalid );
818      break;
819
820    default:
821      FT_INVALID_FORMAT;
822    }
823
824    OTV_EXIT;
825  }
826
827
828  /*************************************************************************/
829  /*************************************************************************/
830  /*****                                                               *****/
831  /*****                     GPOS LOOKUP TYPE 8                        *****/
832  /*****                                                               *****/
833  /*************************************************************************/
834  /*************************************************************************/
835
836  /* sets otvalid->extra1 (lookup count) */
837
838  static void
839  otv_ChainContextPos_validate( FT_Bytes       table,
840                                OTV_Validator  otvalid )
841  {
842    FT_Bytes  p = table;
843    FT_UInt   PosFormat;
844
845
846    OTV_NAME_ENTER( "ChainContextPos" );
847
848    OTV_LIMIT_CHECK( 2 );
849    PosFormat = FT_NEXT_USHORT( p );
850
851    OTV_TRACE(( " (format %d)\n", PosFormat ));
852
853    switch ( PosFormat )
854    {
855    case 1:
856      /* no need to check glyph indices/classes used as input for these */
857      /* context rules since even invalid glyph indices/classes return  */
858      /* meaningful results                                             */
859
860      otvalid->extra1 = otvalid->lookup_count;
861      OTV_NEST3( ChainContextPosFormat1,
862                 ChainPosRuleSet, ChainPosRule );
863      OTV_RUN( table, otvalid );
864      break;
865
866    case 2:
867      /* no need to check glyph indices/classes used as input for these */
868      /* context rules since even invalid glyph indices/classes return  */
869      /* meaningful results                                             */
870
871      OTV_NEST3( ChainContextPosFormat2,
872                 ChainPosClassSet, ChainPosClassRule );
873      OTV_RUN( table, otvalid );
874      break;
875
876    case 3:
877      OTV_NEST1( ChainContextPosFormat3 );
878      OTV_RUN( table, otvalid );
879      break;
880
881    default:
882      FT_INVALID_FORMAT;
883    }
884
885    OTV_EXIT;
886  }
887
888
889  /*************************************************************************/
890  /*************************************************************************/
891  /*****                                                               *****/
892  /*****                     GPOS LOOKUP TYPE 9                        *****/
893  /*****                                                               *****/
894  /*************************************************************************/
895  /*************************************************************************/
896
897  /* uses otvalid->type_funcs */
898
899  static void
900  otv_ExtensionPos_validate( FT_Bytes       table,
901                             OTV_Validator  otvalid )
902  {
903    FT_Bytes  p = table;
904    FT_UInt   PosFormat;
905
906
907    OTV_NAME_ENTER( "ExtensionPos" );
908
909    OTV_LIMIT_CHECK( 2 );
910    PosFormat = FT_NEXT_USHORT( p );
911
912    OTV_TRACE(( " (format %d)\n", PosFormat ));
913
914    switch ( PosFormat )
915    {
916    case 1:     /* ExtensionPosFormat1 */
917      {
918        FT_UInt            ExtensionLookupType;
919        FT_ULong           ExtensionOffset;
920        OTV_Validate_Func  validate;
921
922
923        OTV_LIMIT_CHECK( 6 );
924        ExtensionLookupType = FT_NEXT_USHORT( p );
925        ExtensionOffset     = FT_NEXT_ULONG( p );
926
927        if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
928          FT_INVALID_DATA;
929
930        validate = otvalid->type_funcs[ExtensionLookupType - 1];
931        validate( table + ExtensionOffset, otvalid );
932      }
933      break;
934
935    default:
936      FT_INVALID_FORMAT;
937    }
938
939    OTV_EXIT;
940  }
941
942
943  static const OTV_Validate_Func  otv_gpos_validate_funcs[9] =
944  {
945    otv_SinglePos_validate,
946    otv_PairPos_validate,
947    otv_CursivePos_validate,
948    otv_MarkBasePos_validate,
949    otv_MarkLigPos_validate,
950    otv_MarkMarkPos_validate,
951    otv_ContextPos_validate,
952    otv_ChainContextPos_validate,
953    otv_ExtensionPos_validate
954  };
955
956
957  /* sets otvalid->type_count */
958  /* sets otvalid->type_funcs */
959
960  FT_LOCAL_DEF( void )
961  otv_GPOS_subtable_validate( FT_Bytes       table,
962                              OTV_Validator  otvalid )
963  {
964    otvalid->type_count = 9;
965    otvalid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs;
966
967    otv_Lookup_validate( table, otvalid );
968  }
969
970
971  /*************************************************************************/
972  /*************************************************************************/
973  /*****                                                               *****/
974  /*****                          GPOS TABLE                           *****/
975  /*****                                                               *****/
976  /*************************************************************************/
977  /*************************************************************************/
978
979  /* sets otvalid->glyph_count */
980
981  FT_LOCAL_DEF( void )
982  otv_GPOS_validate( FT_Bytes      table,
983                     FT_UInt       glyph_count,
984                     FT_Validator  ftvalid )
985  {
986    OTV_ValidatorRec  validrec;
987    OTV_Validator     otvalid = &validrec;
988    FT_Bytes          p       = table;
989    FT_UInt           table_size;
990    FT_UShort         version;
991    FT_UInt           ScriptList, FeatureList, LookupList;
992
993    OTV_OPTIONAL_TABLE32( featureVariations );
994
995
996    otvalid->root = ftvalid;
997
998    FT_TRACE3(( "validating GPOS table\n" ));
999    OTV_INIT;
1000
1001    OTV_LIMIT_CHECK( 4 );
1002
1003    if ( FT_NEXT_USHORT( p ) != 1 )  /* majorVersion */
1004      FT_INVALID_FORMAT;
1005
1006    version = FT_NEXT_USHORT( p );   /* minorVersion */
1007
1008    table_size = 10;
1009    switch ( version )
1010    {
1011    case 0:
1012      OTV_LIMIT_CHECK( 6 );
1013      break;
1014
1015    case 1:
1016      OTV_LIMIT_CHECK( 10 );
1017      table_size += 4;
1018      break;
1019
1020    default:
1021      FT_INVALID_FORMAT;
1022    }
1023
1024    ScriptList  = FT_NEXT_USHORT( p );
1025    FeatureList = FT_NEXT_USHORT( p );
1026    LookupList  = FT_NEXT_USHORT( p );
1027
1028    otvalid->type_count  = 9;
1029    otvalid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
1030    otvalid->glyph_count = glyph_count;
1031
1032    otv_LookupList_validate( table + LookupList,
1033                             otvalid );
1034    otv_FeatureList_validate( table + FeatureList, table + LookupList,
1035                              otvalid );
1036    otv_ScriptList_validate( table + ScriptList, table + FeatureList,
1037                             otvalid );
1038
1039    if ( version > 0 )
1040    {
1041      OTV_OPTIONAL_OFFSET32( featureVariations );
1042      OTV_SIZE_CHECK32( featureVariations );
1043      if ( featureVariations )
1044        OTV_TRACE(( "  [omitting featureVariations validation]\n" )); /* XXX */
1045    }
1046
1047    FT_TRACE4(( "\n" ));
1048  }
1049
1050
1051/* END */
1052