Imported Upstream version 2.8
[platform/upstream/freetype2.git] / src / otvalid / otvgpos.c
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         /* 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 - otvalid->extra3;
226
227         OTV_SIZE_CHECK( device );
228         if ( device )
229           otv_Device_validate( otvalid->extra3 + device, otvalid );
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  otvalid )
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, otvalid );
289
290         OTV_SIZE_CHECK( YDeviceTable );
291         if ( YDeviceTable )
292           otv_Device_validate( table + YDeviceTable, otvalid );
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  otvalid )
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 ), otvalid );
335     }
336
337     OTV_EXIT;
338   }
339
340
341   /*************************************************************************/
342   /*************************************************************************/
343   /*****                                                               *****/
344   /*****                     GPOS LOOKUP TYPE 1                        *****/
345   /*****                                                               *****/
346   /*************************************************************************/
347   /*************************************************************************/
348
349   /* sets otvalid->extra3 (pointer to base table) */
350
351   static void
352   otv_SinglePos_validate( FT_Bytes       table,
353                           OTV_Validator  otvalid )
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     otvalid->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, otvalid, -1 );
380         otv_ValueRecord_validate( p, ValueFormat, otvalid ); /* 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,
399                                otvalid,
400                                (FT_Int)ValueCount );
401
402         OTV_LIMIT_CHECK( ValueCount * len_value );
403
404         /* Value */
405         for ( ; ValueCount > 0; ValueCount-- )
406         {
407           otv_ValueRecord_validate( p, ValueFormat, otvalid );
408           p += len_value;
409         }
410       }
411       break;
412
413     default:
414       FT_INVALID_FORMAT;
415     }
416
417     OTV_EXIT;
418   }
419
420
421   /*************************************************************************/
422   /*************************************************************************/
423   /*****                                                               *****/
424   /*****                     GPOS LOOKUP TYPE 2                        *****/
425   /*****                                                               *****/
426   /*************************************************************************/
427   /*************************************************************************/
428
429   static void
430   otv_PairSet_validate( FT_Bytes       table,
431                         FT_UInt        format1,
432                         FT_UInt        format2,
433                         OTV_Validator  otvalid )
434   {
435     FT_Bytes  p = table;
436     FT_UInt   value_len1, value_len2, PairValueCount;
437
438
439     OTV_NAME_ENTER( "PairSet" );
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     otvalid->extra3 = table;
487
488     switch ( PosFormat )
489     {
490     case 1:     /* PairPosFormat1 */
491       {
492         FT_UInt  Coverage, ValueFormat1, ValueFormat2, PairSetCount;
493
494
495         OTV_LIMIT_CHECK( 8 );
496         Coverage     = FT_NEXT_USHORT( p );
497         ValueFormat1 = FT_NEXT_USHORT( p );
498         ValueFormat2 = FT_NEXT_USHORT( p );
499         PairSetCount = FT_NEXT_USHORT( p );
500
501         OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount ));
502
503         otv_Coverage_validate( table + Coverage, otvalid, -1 );
504
505         OTV_LIMIT_CHECK( PairSetCount * 2 );
506
507         /* PairSetOffset */
508         for ( ; PairSetCount > 0; PairSetCount-- )
509           otv_PairSet_validate( table + FT_NEXT_USHORT( p ),
510                                 ValueFormat1, ValueFormat2, otvalid );
511       }
512       break;
513
514     case 2:     /* PairPosFormat2 */
515       {
516         FT_UInt  Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2;
517         FT_UInt  ClassCount1, ClassCount2, len_value1, len_value2, count;
518
519
520         OTV_LIMIT_CHECK( 14 );
521         Coverage     = FT_NEXT_USHORT( p );
522         ValueFormat1 = FT_NEXT_USHORT( p );
523         ValueFormat2 = FT_NEXT_USHORT( p );
524         ClassDef1    = FT_NEXT_USHORT( p );
525         ClassDef2    = FT_NEXT_USHORT( p );
526         ClassCount1  = FT_NEXT_USHORT( p );
527         ClassCount2  = FT_NEXT_USHORT( p );
528
529         OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 ));
530         OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 ));
531
532         len_value1 = otv_value_length( ValueFormat1 );
533         len_value2 = otv_value_length( ValueFormat2 );
534
535         otv_Coverage_validate( table + Coverage, otvalid, -1 );
536         otv_ClassDef_validate( table + ClassDef1, otvalid );
537         otv_ClassDef_validate( table + ClassDef2, otvalid );
538
539         OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
540                      ( len_value1 + len_value2 ) );
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           ScriptList, FeatureList, LookupList;
990
991
992     otvalid->root = ftvalid;
993
994     FT_TRACE3(( "validating GPOS table\n" ));
995     OTV_INIT;
996
997     OTV_LIMIT_CHECK( 10 );
998
999     if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
1000       FT_INVALID_FORMAT;
1001
1002     ScriptList  = FT_NEXT_USHORT( p );
1003     FeatureList = FT_NEXT_USHORT( p );
1004     LookupList  = FT_NEXT_USHORT( p );
1005
1006     otvalid->type_count  = 9;
1007     otvalid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
1008     otvalid->glyph_count = glyph_count;
1009
1010     otv_LookupList_validate( table + LookupList,
1011                              otvalid );
1012     otv_FeatureList_validate( table + FeatureList, table + LookupList,
1013                               otvalid );
1014     otv_ScriptList_validate( table + ScriptList, table + FeatureList,
1015                              otvalid );
1016
1017     FT_TRACE4(( "\n" ));
1018   }
1019
1020
1021 /* END */