otvgpos.c revision 3f1905b191b692e94c3e600ab68f5213aea7caa9
1/***************************************************************************/
2/*                                                                         */
3/*  otvgpos.c                                                              */
4/*                                                                         */
5/*    OpenType GPOS table validation (body).                               */
6/*                                                                         */
7/*  Copyright 2002, 2004, 2005, 2006, 2007 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  valid )
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 * valid->extra1 * 2 );
75
76    table_size = Count * valid->extra1 * 2 + 2;
77
78    for ( ; Count > 0; Count-- )
79      for ( count1 = valid->extra1; count1 > 0; count1-- )
80      {
81        OTV_OPTIONAL_TABLE( anchor_offset );
82
83
84        OTV_OPTIONAL_OFFSET( anchor_offset );
85
86        if ( valid->extra2 )
87        {
88          OTV_SIZE_CHECK( anchor_offset );
89          if ( anchor_offset )
90            otv_Anchor_validate( table + anchor_offset, valid );
91        }
92        else
93          otv_Anchor_validate( table + anchor_offset, valid );
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 valid->extra1 (class count) */
105
106  static void
107  otv_u_O_O_u_O_O( FT_Bytes       table,
108                   OTV_Validator  valid )
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, valid, -1 );
128    otv_Coverage_validate( table + Coverage2, valid, -1 );
129
130    otv_MarkArray_validate( table + Array1, valid );
131
132    valid->nesting_level++;
133    func          = valid->func[valid->nesting_level];
134    valid->extra1 = ClassCount;
135
136    func( table + Array2, valid );
137
138    valid->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 valid->extra3 (pointer to base table) */
167
168  static void
169  otv_ValueRecord_validate( FT_Bytes       table,
170                            FT_UInt        format,
171                            OTV_Validator  valid )
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_UInt   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        /* XXX: this value is usually too small, especially if the current */
222        /* ValueRecord is part of an array -- getting the correct table    */
223        /* size is probably not worth the trouble                          */
224
225        table_size = p - valid->extra3;
226
227        OTV_SIZE_CHECK( device );
228        if ( device )
229          otv_Device_validate( valid->extra3 + device, valid );
230      }
231      format >>= 1;
232    }
233
234    OTV_EXIT;
235  }
236
237
238  /*************************************************************************/
239  /*************************************************************************/
240  /*****                                                               *****/
241  /*****                           ANCHORS                             *****/
242  /*****                                                               *****/
243  /*************************************************************************/
244  /*************************************************************************/
245
246  static void
247  otv_Anchor_validate( FT_Bytes       table,
248                       OTV_Validator  valid )
249  {
250    FT_Bytes  p = table;
251    FT_UInt   AnchorFormat;
252
253
254    OTV_NAME_ENTER( "Anchor");
255
256    OTV_LIMIT_CHECK( 6 );
257    AnchorFormat = FT_NEXT_USHORT( p );
258
259    OTV_TRACE(( " (format %d)\n", AnchorFormat ));
260
261    p += 4;     /* skip XCoordinate and YCoordinate */
262
263    switch ( AnchorFormat )
264    {
265    case 1:
266      break;
267
268    case 2:
269      OTV_LIMIT_CHECK( 2 );  /* AnchorPoint */
270      break;
271
272    case 3:
273      {
274        FT_UInt   table_size;
275
276        OTV_OPTIONAL_TABLE( XDeviceTable );
277        OTV_OPTIONAL_TABLE( YDeviceTable );
278
279
280        OTV_LIMIT_CHECK( 4 );
281        OTV_OPTIONAL_OFFSET( XDeviceTable );
282        OTV_OPTIONAL_OFFSET( YDeviceTable );
283
284        table_size = 6 + 4;
285
286        OTV_SIZE_CHECK( XDeviceTable );
287        if ( XDeviceTable )
288          otv_Device_validate( table + XDeviceTable, valid );
289
290        OTV_SIZE_CHECK( YDeviceTable );
291        if ( YDeviceTable )
292          otv_Device_validate( table + YDeviceTable, valid );
293      }
294      break;
295
296    default:
297      FT_INVALID_FORMAT;
298    }
299
300    OTV_EXIT;
301  }
302
303
304  /*************************************************************************/
305  /*************************************************************************/
306  /*****                                                               *****/
307  /*****                         MARK ARRAYS                           *****/
308  /*****                                                               *****/
309  /*************************************************************************/
310  /*************************************************************************/
311
312  static void
313  otv_MarkArray_validate( FT_Bytes       table,
314                          OTV_Validator  valid )
315  {
316    FT_Bytes  p = table;
317    FT_UInt   MarkCount;
318
319
320    OTV_NAME_ENTER( "MarkArray" );
321
322    OTV_LIMIT_CHECK( 2 );
323    MarkCount = FT_NEXT_USHORT( p );
324
325    OTV_TRACE(( " (MarkCount = %d)\n", MarkCount ));
326
327    OTV_LIMIT_CHECK( MarkCount * 4 );
328
329    /* MarkRecord */
330    for ( ; MarkCount > 0; MarkCount-- )
331    {
332      p += 2;   /* skip Class */
333      /* MarkAnchor */
334      otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid );
335    }
336
337    OTV_EXIT;
338  }
339
340
341  /*************************************************************************/
342  /*************************************************************************/
343  /*****                                                               *****/
344  /*****                     GPOS LOOKUP TYPE 1                        *****/
345  /*****                                                               *****/
346  /*************************************************************************/
347  /*************************************************************************/
348
349  /* sets valid->extra3 (pointer to base table) */
350
351  static void
352  otv_SinglePos_validate( FT_Bytes       table,
353                          OTV_Validator  valid )
354  {
355    FT_Bytes  p = table;
356    FT_UInt   PosFormat;
357
358
359    OTV_NAME_ENTER( "SinglePos" );
360
361    OTV_LIMIT_CHECK( 2 );
362    PosFormat = FT_NEXT_USHORT( p );
363
364    OTV_TRACE(( " (format %d)\n", PosFormat ));
365
366    valid->extra3 = table;
367
368    switch ( PosFormat )
369    {
370    case 1:     /* SinglePosFormat1 */
371      {
372        FT_UInt  Coverage, ValueFormat;
373
374
375        OTV_LIMIT_CHECK( 4 );
376        Coverage    = FT_NEXT_USHORT( p );
377        ValueFormat = FT_NEXT_USHORT( p );
378
379        otv_Coverage_validate( table + Coverage, valid, -1 );
380        otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */
381      }
382      break;
383
384    case 2:     /* SinglePosFormat2 */
385      {
386        FT_UInt  Coverage, ValueFormat, ValueCount, len_value;
387
388
389        OTV_LIMIT_CHECK( 6 );
390        Coverage    = FT_NEXT_USHORT( p );
391        ValueFormat = FT_NEXT_USHORT( p );
392        ValueCount  = FT_NEXT_USHORT( p );
393
394        OTV_TRACE(( " (ValueCount = %d)\n", ValueCount ));
395
396        len_value = otv_value_length( ValueFormat );
397
398        otv_Coverage_validate( table + Coverage, valid, ValueCount );
399
400        OTV_LIMIT_CHECK( ValueCount * len_value );
401
402        /* Value */
403        for ( ; ValueCount > 0; ValueCount-- )
404        {
405          otv_ValueRecord_validate( p, ValueFormat, valid );
406          p += len_value;
407        }
408      }
409      break;
410
411    default:
412      FT_INVALID_FORMAT;
413    }
414
415    OTV_EXIT;
416  }
417
418
419  /*************************************************************************/
420  /*************************************************************************/
421  /*****                                                               *****/
422  /*****                     GPOS LOOKUP TYPE 2                        *****/
423  /*****                                                               *****/
424  /*************************************************************************/
425  /*************************************************************************/
426
427  static void
428  otv_PairSet_validate( FT_Bytes       table,
429                        FT_UInt        format1,
430                        FT_UInt        format2,
431                        OTV_Validator  valid )
432  {
433    FT_Bytes  p = table;
434    FT_UInt   value_len1, value_len2, PairValueCount;
435
436
437    OTV_NAME_ENTER( "PairSet" );
438
439    OTV_LIMIT_CHECK( 2 );
440    PairValueCount = FT_NEXT_USHORT( p );
441
442    OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount ));
443
444    value_len1 = otv_value_length( format1 );
445    value_len2 = otv_value_length( format2 );
446
447    OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) );
448
449    /* PairValueRecord */
450    for ( ; PairValueCount > 0; PairValueCount-- )
451    {
452      p += 2;       /* skip SecondGlyph */
453
454      if ( format1 )
455        otv_ValueRecord_validate( p, format1, valid ); /* Value1 */
456      p += value_len1;
457
458      if ( format2 )
459        otv_ValueRecord_validate( p, format2, valid ); /* Value2 */
460      p += value_len2;
461    }
462
463    OTV_EXIT;
464  }
465
466
467  /* sets valid->extra3 (pointer to base table) */
468
469  static void
470  otv_PairPos_validate( FT_Bytes       table,
471                        OTV_Validator  valid )
472  {
473    FT_Bytes  p = table;
474    FT_UInt   PosFormat;
475
476
477    OTV_NAME_ENTER( "PairPos" );
478
479    OTV_LIMIT_CHECK( 2 );
480    PosFormat = FT_NEXT_USHORT( p );
481
482    OTV_TRACE(( " (format %d)\n", PosFormat ));
483
484    valid->extra3 = table;
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, valid, -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, valid );
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, valid, -1 );
534        otv_ClassDef_validate( table + ClassDef1, valid );
535        otv_ClassDef_validate( table + ClassDef2, valid );
536
537        OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
538                     ( len_value1 + len_value2 ) );
539
540        /* Class1Record */
541        for ( ; ClassCount1 > 0; ClassCount1-- )
542        {
543          /* Class2Record */
544          for ( count = ClassCount2; count > 0; count-- )
545          {
546            if ( ValueFormat1 )
547              /* Value1 */
548              otv_ValueRecord_validate( p, ValueFormat1, valid );
549            p += len_value1;
550
551            if ( ValueFormat2 )
552              /* Value2 */
553              otv_ValueRecord_validate( p, ValueFormat2, valid );
554            p += len_value2;
555          }
556        }
557      }
558      break;
559
560    default:
561      FT_INVALID_FORMAT;
562    }
563
564    OTV_EXIT;
565  }
566
567
568  /*************************************************************************/
569  /*************************************************************************/
570  /*****                                                               *****/
571  /*****                     GPOS LOOKUP TYPE 3                        *****/
572  /*****                                                               *****/
573  /*************************************************************************/
574  /*************************************************************************/
575
576  static void
577  otv_CursivePos_validate( FT_Bytes       table,
578                           OTV_Validator  valid )
579  {
580    FT_Bytes  p = table;
581    FT_UInt   PosFormat;
582
583
584    OTV_NAME_ENTER( "CursivePos" );
585
586    OTV_LIMIT_CHECK( 2 );
587    PosFormat = FT_NEXT_USHORT( p );
588
589    OTV_TRACE(( " (format %d)\n", PosFormat ));
590
591    switch ( PosFormat )
592    {
593    case 1:     /* CursivePosFormat1 */
594      {
595        FT_UInt   table_size;
596        FT_UInt   Coverage, EntryExitCount;
597
598        OTV_OPTIONAL_TABLE( EntryAnchor );
599        OTV_OPTIONAL_TABLE( ExitAnchor  );
600
601
602        OTV_LIMIT_CHECK( 4 );
603        Coverage       = FT_NEXT_USHORT( p );
604        EntryExitCount = FT_NEXT_USHORT( p );
605
606        OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
607
608        otv_Coverage_validate( table + Coverage, valid, EntryExitCount );
609
610        OTV_LIMIT_CHECK( EntryExitCount * 4 );
611
612        table_size = EntryExitCount * 4 + 4;
613
614        /* EntryExitRecord */
615        for ( ; EntryExitCount > 0; EntryExitCount-- )
616        {
617          OTV_OPTIONAL_OFFSET( EntryAnchor );
618          OTV_OPTIONAL_OFFSET( ExitAnchor  );
619
620          OTV_SIZE_CHECK( EntryAnchor );
621          if ( EntryAnchor )
622            otv_Anchor_validate( table + EntryAnchor, valid );
623
624          OTV_SIZE_CHECK( ExitAnchor );
625          if ( ExitAnchor )
626            otv_Anchor_validate( table + ExitAnchor, valid );
627        }
628      }
629      break;
630
631    default:
632      FT_INVALID_FORMAT;
633    }
634
635    OTV_EXIT;
636  }
637
638
639  /*************************************************************************/
640  /*************************************************************************/
641  /*****                                                               *****/
642  /*****                     GPOS LOOKUP TYPE 4                        *****/
643  /*****                                                               *****/
644  /*************************************************************************/
645  /*************************************************************************/
646
647  /* sets valid->extra2 (0) */
648
649  static void
650  otv_MarkBasePos_validate( FT_Bytes       table,
651                            OTV_Validator  valid )
652  {
653    FT_Bytes  p = table;
654    FT_UInt   PosFormat;
655
656
657    OTV_NAME_ENTER( "MarkBasePos" );
658
659    OTV_LIMIT_CHECK( 2 );
660    PosFormat = FT_NEXT_USHORT( p );
661
662    OTV_TRACE(( " (format %d)\n", PosFormat ));
663
664    switch ( PosFormat )
665    {
666    case 1:
667      valid->extra2 = 0;
668      OTV_NEST2( MarkBasePosFormat1, BaseArray );
669      OTV_RUN( table, valid );
670      break;
671
672    default:
673      FT_INVALID_FORMAT;
674    }
675
676    OTV_EXIT;
677  }
678
679
680  /*************************************************************************/
681  /*************************************************************************/
682  /*****                                                               *****/
683  /*****                     GPOS LOOKUP TYPE 5                        *****/
684  /*****                                                               *****/
685  /*************************************************************************/
686  /*************************************************************************/
687
688  /* sets valid->extra2 (1) */
689
690  static void
691  otv_MarkLigPos_validate( FT_Bytes       table,
692                           OTV_Validator  valid )
693  {
694    FT_Bytes  p = table;
695    FT_UInt   PosFormat;
696
697
698    OTV_NAME_ENTER( "MarkLigPos" );
699
700    OTV_LIMIT_CHECK( 2 );
701    PosFormat = FT_NEXT_USHORT( p );
702
703    OTV_TRACE(( " (format %d)\n", PosFormat ));
704
705    switch ( PosFormat )
706    {
707    case 1:
708      valid->extra2 = 1;
709      OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
710      OTV_RUN( table, valid );
711      break;
712
713    default:
714      FT_INVALID_FORMAT;
715    }
716
717    OTV_EXIT;
718  }
719
720
721  /*************************************************************************/
722  /*************************************************************************/
723  /*****                                                               *****/
724  /*****                     GPOS LOOKUP TYPE 6                        *****/
725  /*****                                                               *****/
726  /*************************************************************************/
727  /*************************************************************************/
728
729  /* sets valid->extra2 (0) */
730
731  static void
732  otv_MarkMarkPos_validate( FT_Bytes       table,
733                            OTV_Validator  valid )
734  {
735    FT_Bytes  p = table;
736    FT_UInt   PosFormat;
737
738
739    OTV_NAME_ENTER( "MarkMarkPos" );
740
741    OTV_LIMIT_CHECK( 2 );
742    PosFormat = FT_NEXT_USHORT( p );
743
744    OTV_TRACE(( " (format %d)\n", PosFormat ));
745
746    switch ( PosFormat )
747    {
748    case 1:
749      valid->extra2 = 0;
750      OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
751      OTV_RUN( table, valid );
752      break;
753
754    default:
755      FT_INVALID_FORMAT;
756    }
757
758    OTV_EXIT;
759  }
760
761
762  /*************************************************************************/
763  /*************************************************************************/
764  /*****                                                               *****/
765  /*****                     GPOS LOOKUP TYPE 7                        *****/
766  /*****                                                               *****/
767  /*************************************************************************/
768  /*************************************************************************/
769
770  /* sets valid->extra1 (lookup count) */
771
772  static void
773  otv_ContextPos_validate( FT_Bytes       table,
774                           OTV_Validator  valid )
775  {
776    FT_Bytes  p = table;
777    FT_UInt   PosFormat;
778
779
780    OTV_NAME_ENTER( "ContextPos" );
781
782    OTV_LIMIT_CHECK( 2 );
783    PosFormat = FT_NEXT_USHORT( p );
784
785    OTV_TRACE(( " (format %d)\n", PosFormat ));
786
787    switch ( PosFormat )
788    {
789    case 1:
790      /* no need to check glyph indices/classes used as input for these */
791      /* context rules since even invalid glyph indices/classes return  */
792      /* meaningful results                                             */
793
794      valid->extra1 = valid->lookup_count;
795      OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
796      OTV_RUN( table, valid );
797      break;
798
799    case 2:
800      /* no need to check glyph indices/classes used as input for these */
801      /* context rules since even invalid glyph indices/classes return  */
802      /* meaningful results                                             */
803
804      OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
805      OTV_RUN( table, valid );
806      break;
807
808    case 3:
809      OTV_NEST1( ContextPosFormat3 );
810      OTV_RUN( table, valid );
811      break;
812
813    default:
814      FT_INVALID_FORMAT;
815    }
816
817    OTV_EXIT;
818  }
819
820
821  /*************************************************************************/
822  /*************************************************************************/
823  /*****                                                               *****/
824  /*****                     GPOS LOOKUP TYPE 8                        *****/
825  /*****                                                               *****/
826  /*************************************************************************/
827  /*************************************************************************/
828
829  /* sets valid->extra1 (lookup count) */
830
831  static void
832  otv_ChainContextPos_validate( FT_Bytes       table,
833                                OTV_Validator  valid )
834  {
835    FT_Bytes  p = table;
836    FT_UInt   PosFormat;
837
838
839    OTV_NAME_ENTER( "ChainContextPos" );
840
841    OTV_LIMIT_CHECK( 2 );
842    PosFormat = FT_NEXT_USHORT( p );
843
844    OTV_TRACE(( " (format %d)\n", PosFormat ));
845
846    switch ( PosFormat )
847    {
848    case 1:
849      /* no need to check glyph indices/classes used as input for these */
850      /* context rules since even invalid glyph indices/classes return  */
851      /* meaningful results                                             */
852
853      valid->extra1 = valid->lookup_count;
854      OTV_NEST3( ChainContextPosFormat1,
855                 ChainPosRuleSet, ChainPosRule );
856      OTV_RUN( table, valid );
857      break;
858
859    case 2:
860      /* no need to check glyph indices/classes used as input for these */
861      /* context rules since even invalid glyph indices/classes return  */
862      /* meaningful results                                             */
863
864      OTV_NEST3( ChainContextPosFormat2,
865                 ChainPosClassSet, ChainPosClassRule );
866      OTV_RUN( table, valid );
867      break;
868
869    case 3:
870      OTV_NEST1( ChainContextPosFormat3 );
871      OTV_RUN( table, valid );
872      break;
873
874    default:
875      FT_INVALID_FORMAT;
876    }
877
878    OTV_EXIT;
879  }
880
881
882  /*************************************************************************/
883  /*************************************************************************/
884  /*****                                                               *****/
885  /*****                     GPOS LOOKUP TYPE 9                        *****/
886  /*****                                                               *****/
887  /*************************************************************************/
888  /*************************************************************************/
889
890  /* uses valid->type_funcs */
891
892  static void
893  otv_ExtensionPos_validate( FT_Bytes       table,
894                             OTV_Validator  valid )
895  {
896    FT_Bytes  p = table;
897    FT_UInt   PosFormat;
898
899
900    OTV_NAME_ENTER( "ExtensionPos" );
901
902    OTV_LIMIT_CHECK( 2 );
903    PosFormat = FT_NEXT_USHORT( p );
904
905    OTV_TRACE(( " (format %d)\n", PosFormat ));
906
907    switch ( PosFormat )
908    {
909    case 1:     /* ExtensionPosFormat1 */
910      {
911        FT_UInt            ExtensionLookupType, ExtensionOffset;
912        OTV_Validate_Func  validate;
913
914
915        OTV_LIMIT_CHECK( 6 );
916        ExtensionLookupType = FT_NEXT_USHORT( p );
917        ExtensionOffset     = FT_NEXT_ULONG( p );
918
919        if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
920          FT_INVALID_DATA;
921
922        validate = valid->type_funcs[ExtensionLookupType - 1];
923        validate( table + ExtensionOffset, valid );
924      }
925      break;
926
927    default:
928      FT_INVALID_FORMAT;
929    }
930
931    OTV_EXIT;
932  }
933
934
935  static const OTV_Validate_Func  otv_gpos_validate_funcs[9] =
936  {
937    otv_SinglePos_validate,
938    otv_PairPos_validate,
939    otv_CursivePos_validate,
940    otv_MarkBasePos_validate,
941    otv_MarkLigPos_validate,
942    otv_MarkMarkPos_validate,
943    otv_ContextPos_validate,
944    otv_ChainContextPos_validate,
945    otv_ExtensionPos_validate
946  };
947
948
949  /* sets valid->type_count */
950  /* sets valid->type_funcs */
951
952  FT_LOCAL_DEF( void )
953  otv_GPOS_subtable_validate( FT_Bytes       table,
954                              OTV_Validator  valid )
955  {
956    valid->type_count = 9;
957    valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs;
958
959    otv_Lookup_validate( table, valid );
960  }
961
962
963  /*************************************************************************/
964  /*************************************************************************/
965  /*****                                                               *****/
966  /*****                          GPOS TABLE                           *****/
967  /*****                                                               *****/
968  /*************************************************************************/
969  /*************************************************************************/
970
971  /* sets valid->glyph_count */
972
973  FT_LOCAL_DEF( void )
974  otv_GPOS_validate( FT_Bytes      table,
975                     FT_UInt       glyph_count,
976                     FT_Validator  ftvalid )
977  {
978    OTV_ValidatorRec  validrec;
979    OTV_Validator     valid = &validrec;
980    FT_Bytes          p     = table;
981    FT_UInt           ScriptList, FeatureList, LookupList;
982
983
984    valid->root = ftvalid;
985
986    FT_TRACE3(( "validating GPOS table\n" ));
987    OTV_INIT;
988
989    OTV_LIMIT_CHECK( 10 );
990
991    if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
992      FT_INVALID_FORMAT;
993
994    ScriptList  = FT_NEXT_USHORT( p );
995    FeatureList = FT_NEXT_USHORT( p );
996    LookupList  = FT_NEXT_USHORT( p );
997
998    valid->type_count  = 9;
999    valid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
1000    valid->glyph_count = glyph_count;
1001
1002    otv_LookupList_validate( table + LookupList,
1003                             valid );
1004    otv_FeatureList_validate( table + FeatureList, table + LookupList,
1005                              valid );
1006    otv_ScriptList_validate( table + ScriptList, table + FeatureList,
1007                             valid );
1008
1009    FT_TRACE4(( "\n" ));
1010  }
1011
1012
1013/* END */
1014