1 /****************************************************************************
2  *
3  * otvgpos.c
4  *
5  *   OpenType GPOS table validation (body).
6  *
7  * Copyright (C) 2002-2019 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
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         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
otv_Anchor_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_MarkArray_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_SinglePos_validate(FT_Bytes table,OTV_Validator otvalid)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
otv_PairSet_validate(FT_Bytes table,FT_UInt format1,FT_UInt format2,OTV_Validator otvalid)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
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     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
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           table_size;
990     FT_UShort         version;
991     FT_UInt           ScriptList, FeatureList, LookupList;
992 
993     OTV_OPTIONAL_TABLE32( featureVariations );
994 
995 
996     otvalid->root = ftvalid;
997 
998     FT_TRACE3(( "validating GPOS table\n" ));
999     OTV_INIT;
1000 
1001     OTV_LIMIT_CHECK( 4 );
1002 
1003     if ( FT_NEXT_USHORT( p ) != 1 )  /* majorVersion */
1004       FT_INVALID_FORMAT;
1005 
1006     version = FT_NEXT_USHORT( p );   /* minorVersion */
1007 
1008     table_size = 10;
1009     switch ( version )
1010     {
1011     case 0:
1012       OTV_LIMIT_CHECK( 6 );
1013       break;
1014 
1015     case 1:
1016       OTV_LIMIT_CHECK( 10 );
1017       table_size += 4;
1018       break;
1019 
1020     default:
1021       FT_INVALID_FORMAT;
1022     }
1023 
1024     ScriptList  = FT_NEXT_USHORT( p );
1025     FeatureList = FT_NEXT_USHORT( p );
1026     LookupList  = FT_NEXT_USHORT( p );
1027 
1028     otvalid->type_count  = 9;
1029     otvalid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
1030     otvalid->glyph_count = glyph_count;
1031 
1032     otv_LookupList_validate( table + LookupList,
1033                              otvalid );
1034     otv_FeatureList_validate( table + FeatureList, table + LookupList,
1035                               otvalid );
1036     otv_ScriptList_validate( table + ScriptList, table + FeatureList,
1037                              otvalid );
1038 
1039     if ( version > 0 )
1040     {
1041       OTV_OPTIONAL_OFFSET32( featureVariations );
1042       OTV_SIZE_CHECK32( featureVariations );
1043       if ( featureVariations )
1044         OTV_TRACE(( "  [omitting featureVariations validation]\n" )); /* XXX */
1045     }
1046 
1047     FT_TRACE4(( "\n" ));
1048   }
1049 
1050 
1051 /* END */
1052