1 /***************************************************************************/
2 /*                                                                         */
3 /*  otvgpos.c                                                              */
4 /*                                                                         */
5 /*    OpenType GPOS table validation (body).                               */
6 /*                                                                         */
7 /*  Copyright 2002-2016 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
otv_x_sxy(FT_Bytes table,OTV_Validator otvalid)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
otv_u_O_O_u_O_O(FT_Bytes table,OTV_Validator otvalid)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
otv_value_length(FT_UInt format)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
otv_ValueRecord_validate(FT_Bytes table,FT_UInt format,OTV_Validator otvalid)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
otv_Anchor_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_MarkArray_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_SinglePos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_PairSet_validate(FT_Bytes table,FT_UInt format1,FT_UInt format2,OTV_Validator otvalid)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
otv_PairPos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_CursivePos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_MarkBasePos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_MarkLigPos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_MarkMarkPos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_ContextPos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_ChainContextPos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_ExtensionPos_validate(FT_Bytes table,OTV_Validator otvalid)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 )
otv_GPOS_subtable_validate(FT_Bytes table,OTV_Validator otvalid)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 )
otv_GPOS_validate(FT_Bytes table,FT_UInt glyph_count,FT_Validator ftvalid)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 */
1022