Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / src / otvalid / otvgpos.c
1 /****************************************************************************
2  *
3  * otvgpos.c
4  *
5  *   OpenType GPOS table validation (body).
6  *
7  * Copyright (C) 2002-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 #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  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 */