xref: /inferno-os/libfreetype/otlgsub.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 #include "otlgsub.h"
2 #include "otlcommn.h"
3 
4  /************************************************************************/
5  /************************************************************************/
6  /*****                                                              *****/
7  /*****                 GSUB LOOKUP TYPE 1                           *****/
8  /*****                                                              *****/
9  /************************************************************************/
10  /************************************************************************/
11 
12  /*
13   *  1: Single Substitution - Table format(s)
14   *
15   *  This table is used to substiture individual glyph indices
16   *  with another one. There are only two sub-formats:
17   *
18   *   Name         Offset    Size       Description
19   *   ------------------------------------------
20   *   format       0         2          sub-table format (1)
21   *   offset       2         2          offset to coverage table
22   *   delta        4         2          16-bit delta to apply on all
23   *                                     covered glyph indices
24   *
25   *   Name         Offset    Size       Description
26   *   ------------------------------------------
27   *   format       0         2          sub-table format (2)
28   *   offset       2         2          offset to coverage table
29   *   count        4         2          coverage table count
30   *   substs[]     6         2*count    substituted glyph indices,
31   *
32   */
33 
34   static void
otl_gsub_lookup1_validate(OTL_Bytes table,OTL_Validator valid)35   otl_gsub_lookup1_validate( OTL_Bytes      table,
36                              OTL_Validator  valid )
37   {
38     OTL_Bytes  p = table;
39     OTL_UInt   format;
40 
41     OTL_CHECK( 2 );
42     format = OTL_NEXT_USHORT( p );
43     switch ( format )
44     {
45       case 1:
46         {
47           OTL_UInt  coverage;
48 
49           OTL_CHECK( 4 );
50           coverage = OTL_NEXT_USHORT( p );
51 
52           otl_coverage_validate( table + coverage, valid );
53         }
54         break;
55 
56       case 2:
57         {
58           OTL_UInt  coverage, count;
59 
60           OTL_CHECK( 4 );
61           coverage = OTL_NEXT_USHORT( p );
62           count    = OTL_NEXT_USHORT( p );
63 
64           otl_coverage_validate( table + coverage, valid );
65 
66           OTL_CHECK( 2*count );
67 
68           /* NB: we don't check that there are at most 'count'   */
69           /*     elements in the coverage table. This is delayed */
70           /*     to the lookup function...                       */
71         }
72         break;
73 
74       default:
75         OTL_INVALID_DATA;
76     }
77   }
78 
79 
80   static OTL_Bool
otl_gsub_lookup1_apply(OTL_Bytes table,OTL_Parser parser)81   otl_gsub_lookup1_apply( OTL_Bytes   table,
82                           OTL_Parser  parser )
83   {
84     OTL_Bytes  p = table;
85     OTL_Bytes  coverage;
86     OTL_UInt   format, gindex, property;
87     OTL_Int    index;
88     OTL_Bool   subst = 0;
89 
90     if ( parser->context_len != 0xFFFF && parser->context_len < 1 )
91       goto Exit;
92 
93     gindex = otl_parser_get_gindex( parser );
94 
95     if ( !otl_parser_check_property( parser, gindex, &property ) )
96       goto Exit;
97 
98     format   = OTL_NEXT_USHORT(p);
99     coverage = table + OTL_NEXT_USHORT(p);
100     index    = otl_coverage_lookup( coverage, gindex );
101 
102     if ( index >= 0 )
103     {
104       switch ( format )
105       {
106         case 1:
107           {
108             OTL_Int  delta = OTL_NEXT_SHORT(p);
109 
110             gindex = ( gindex + delta ) & 0xFFFF;
111             otl_parser_replace_1( parser, gindex );
112             subst = 1;
113           }
114           break;
115 
116         case 2:
117           {
118             OTL_UInt  count = OTL_NEXT_USHORT(p);
119 
120             if ( (OTL_UInt) index < count )
121             {
122               p += index*2;
123               otl_parser_replace_1( parser, OTL_PEEK_USHORT(p) );
124               subst = 1;
125             }
126           }
127           break;
128 
129         default:
130           ;
131       }
132     }
133   Exit:
134     return subst;
135   }
136 
137  /************************************************************************/
138  /************************************************************************/
139  /*****                                                              *****/
140  /*****                 GSUB LOOKUP TYPE 2                           *****/
141  /*****                                                              *****/
142  /************************************************************************/
143  /************************************************************************/
144 
145  /*
146   *  2: Multiple Substitution - Table format(s)
147   *
148   *  Replaces a single glyph with one or more glyphs.
149   *
150   *   Name         Offset    Size       Description
151   *   -----------------------------------------------------------
152   *   format       0         2          sub-table format (1)
153   *   offset       2         2          offset to coverage table
154   *   count        4         2          coverage table count
155   *   sequencess[] 6         2*count    offsets to sequence items
156   *
157   *   each sequence item has the following format:
158   *
159   *   Name         Offset    Size       Description
160   *   -----------------------------------------------------------
161   *   count        0         2          number of replacement glyphs
162   *   gindices[]   2         2*count    string of glyph indices
163   */
164 
165   static void
otl_seq_validate(OTL_Bytes table,OTL_Validator valid)166   otl_seq_validate( OTL_Bytes      table,
167                     OTL_Validator  valid )
168   {
169     OTL_Bytes  p = table;
170     OTL_UInt   count;
171 
172     OTL_CHECK( 2 );
173     count = OTL_NEXT_USHORT( p );
174 
175     /* XXX: according to the spec, 'count' should be > 0     */
176     /*      we can deal with these cases pretty well however */
177 
178     OTL_CHECK( 2*count );
179     /* check glyph indices */
180   }
181 
182 
183   static void
otl_gsub_lookup2_validate(OTL_Bytes table,OTL_Validator valid)184   otl_gsub_lookup2_validate( OTL_Bytes      table,
185                              OTL_Validator  valid )
186   {
187     OTL_Bytes  p = table;
188     OTL_UInt   format, coverage;
189 
190     OTL_CHECK( 2 );
191     format = OTL_NEXT_USHORT( p );
192     switch ( format )
193     {
194       case 1:
195         {
196           OTL_UInt  coverage, seq_count;
197 
198           OTL_CHECK( 4 );
199           coverage  = OTL_NEXT_USHORT( p );
200           seq_count = OTL_NEXT_USHORT( p );
201 
202           otl_coverage_validate( table + coverage, valid );
203 
204           OTL_CHECK( seq_count*2 );
205           for ( ; seq_count > 0; seq_count-- )
206             otl_seq_validate( table + OTL_NEXT_USHORT( p ), valid );
207         }
208         break;
209 
210       default:
211         OTL_INVALID_DATA;
212     }
213   }
214 
215 
216   static OTL_Bool
otl_gsub_lookup2_apply(OTL_Bytes table,OTL_Parser parser)217   otl_gsub_lookup2_apply( OTL_Bytes    table,
218                           OTL_Parser   parser )
219   {
220     OTL_Bytes  p = table;
221     OTL_Bytes  coverage, sequence;
222     OTL_UInt   format, gindex, index, property;
223     OTL_Int    index;
224     OTL_Bool   subst = 0;
225 
226     if ( context_len != 0xFFFF && context_len < 1 )
227       goto Exit;
228 
229     gindex = otl_parser_get_gindex( parser );
230 
231     if ( !otl_parser_check_property( parser, gindex, &property ) )
232       goto Exit;
233 
234     p        += 2;  /* skip format */
235     coverage  = table + OTL_NEXT_USHORT(p);
236     seq_count = OTL_NEXT_USHORT(p);
237     index     = otl_coverage_lookup( coverage, gindex );
238 
239     if ( (OTL_UInt) index >= seq_count )
240       goto Exit;
241 
242     p       += index*2;
243     sequence = table + OTL_PEEK_USHORT(p);
244     p        = sequence;
245     count    = OTL_NEXT_USHORT(p);
246 
247     otl_parser_replace_n( parser, count, p );
248     subst = 1;
249 
250    Exit:
251     return subst;
252   }
253 
254  /************************************************************************/
255  /************************************************************************/
256  /*****                                                              *****/
257  /*****                 GSUB LOOKUP TYPE 3                           *****/
258  /*****                                                              *****/
259  /************************************************************************/
260  /************************************************************************/
261 
262  /*
263   *  3: Alternate Substitution - Table format(s)
264   *
265   *  Replaces a single glyph by another one taken liberally
266   *  in a list of alternatives
267   *
268   *   Name         Offset    Size       Description
269   *   -----------------------------------------------------------
270   *   format       0         2          sub-table format (1)
271   *   offset       2         2          offset to coverage table
272   *   count        4         2          coverage table count
273   *   alternates[] 6         2*count    offsets to alternate items
274   *
275   *   each alternate item has the following format:
276   *
277   *   Name         Offset    Size       Description
278   *   -----------------------------------------------------------
279   *   count        0         2          number of replacement glyphs
280   *   gindices[]   2         2*count    string of glyph indices, each one
281   *                                     is a valid alternative
282   */
283 
284   static void
otl_alternate_set_validate(OTL_Bytes table,OTL_Validator valid)285   otl_alternate_set_validate( OTL_Bytes      table,
286                               OTL_Validator  valid )
287   {
288     OTL_Bytes  p = table;
289     OTL_UInt   count;
290 
291     OTL_CHECK( 2 );
292     count = OTL_NEXT_USHORT( p );
293 
294     OTL_CHECK( 2*count );
295     /* XXX: check glyph indices */
296   }
297 
298 
299   static void
otl_gsub_lookup3_validate(OTL_Bytes table,OTL_Validator valid)300   otl_gsub_lookup3_validate( OTL_Bytes      table,
301                              OTL_Validator  valid )
302   {
303     OTL_Bytes  p = table;
304     OTL_UInt   format, coverage;
305 
306     OTL_CHECK( 2 );
307     format = OTL_NEXT_USHORT( p );
308     switch ( format )
309     {
310       case 1:
311         {
312           OTL_UInt  coverage, count;
313 
314           OTL_CHECK( 4 );
315           coverage = OTL_NEXT_USHORT( p );
316           count    = OTL_NEXT_USHORT( p );
317 
318           otl_coverage_validate( table + coverage, valid );
319 
320           OTL_CHECK( 2*count );
321           for ( ; count > 0; count-- )
322             otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid );
323         }
324         break;
325 
326       default:
327         OTL_INVALID_DATA;
328     }
329   }
330 
331 
332   static OTL_Bool
otl_gsub_lookup3_apply(OTL_Bytes table,OTL_Parser parser)333   otl_gsub_lookup3_apply( OTL_Bytes    table,
334                           OTL_Parser   parser )
335   {
336     OTL_Bytes  p = table;
337     OTL_Bytes  coverage, alternates;
338     OTL_UInt   format, gindex, index, property;
339     OTL_Int    index;
340     OTL_Bool   subst = 0;
341 
342     OTL_GSUB_Alternate  alternate = parser->alternate;
343 
344     if ( context_len != 0xFFFF && context_len < 1 )
345       goto Exit;
346 
347     if ( alternate == NULL )
348       goto Exit;
349 
350     gindex = otl_parser_get_gindex( parser );
351 
352     if ( !otl_parser_check_property( parser, gindex, &property ) )
353       goto Exit;
354 
355     p        += 2;  /* skip format */
356     coverage  = table + OTL_NEXT_USHORT(p);
357     seq_count = OTL_NEXT_USHORT(p);
358     index     = otl_coverage_lookup( coverage, gindex );
359 
360     if ( (OTL_UInt) index >= seq_count )
361       goto Exit;
362 
363     p         += index*2;
364     alternates = table + OTL_PEEK_USHORT(p);
365     p          = alternates;
366     count      = OTL_NEXT_USHORT(p);
367 
368     gindex = alternate->handler_func(
369                  gindex, count, p, alternate->handler_data );
370 
371     otl_parser_replace_1( parser, gindex );
372     subst = 1;
373 
374    Exit:
375     return subst;
376   }
377 
378  /************************************************************************/
379  /************************************************************************/
380  /*****                                                              *****/
381  /*****                 GSUB LOOKUP TYPE 4                           *****/
382  /*****                                                              *****/
383  /************************************************************************/
384  /************************************************************************/
385 
386   static void
otl_ligature_validate(OTL_Bytes table,OTL_Validator valid)387   otl_ligature_validate( OTL_Bytes      table,
388                          OTL_Validator  valid )
389   {
390     OTL_UInt  glyph_id, count;
391 
392     OTL_CHECK( 4 );
393     glyph_id = OTL_NEXT_USHORT( p );
394     count    = OTL_NEXT_USHORT( p );
395 
396     if ( count == 0 )
397       OTL_INVALID_DATA;
398 
399     OTL_CHECK( 2*(count-1) );
400     /* XXX: check glyph indices */
401   }
402 
403 
404   static void
otl_ligature_set_validate(OTL_Bytes table,OTL_Validator valid)405   otl_ligature_set_validate( OTL_Bytes      table,
406                              OTL_Validator  valid )
407   {
408     OTL_Bytes  p = table;
409     OTL_UInt   count;
410 
411     OTL_CHECK( 2 );
412     count = OTL_NEXT_USHORT( p );
413 
414     OTL_CHECK( 2*count );
415     for ( ; count > 0; count-- )
416       otl_ligature_validate( table + OTL_NEXT_USHORT( p ), valid );
417   }
418 
419 
420   static void
otl_gsub_lookup4_validate(OTL_Bytes table,OTL_Validator valid)421   otl_gsub_lookup4_validate( OTL_Bytes      table,
422                              OTL_Validator  valid )
423   {
424     OTL_Bytes  p = table;
425     OTL_UInt   format, coverage;
426 
427     OTL_CHECK( 2 );
428     format = OTL_NEXT_USHORT( p );
429     switch ( format )
430     {
431       case 1:
432         {
433           OTL_UInt  coverage, count;
434 
435           OTL_CHECK( 4 );
436           coverage = OTL_NEXT_USHORT( p );
437           count    = OTL_NEXT_USHORT( p );
438 
439           otl_coverage_validate( table + coverage, valid );
440 
441           OTL_CHECK( 2*count );
442           for ( ; count > 0; count-- )
443             otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid );
444         }
445         break;
446 
447       default:
448         OTL_INVALID_DATA;
449     }
450   }
451 
452 
453  /************************************************************************/
454  /************************************************************************/
455  /*****                                                              *****/
456  /*****                 GSUB LOOKUP TYPE 5                           *****/
457  /*****                                                              *****/
458  /************************************************************************/
459  /************************************************************************/
460 
461 
462   static void
otl_sub_rule_validate(OTL_Bytes table,OTL_Validator valid)463   otl_sub_rule_validate( OTL_Bytes      table,
464                          OTL_Validator  valid )
465   {
466     OTL_Bytes  p = table;
467     OTL_UInt   glyph_count, subst_count;
468 
469     OTL_CHECK( 4 );
470     glyph_count = OTL_NEXT_USHORT( p );
471     subst_count = OTL_NEXT_USHORT( p );
472 
473     if ( glyph_count == 0 )
474       OTL_INVALID_DATA;
475 
476     OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
477 
478     /* XXX: check glyph indices and subst lookups */
479   }
480 
481 
482   static void
otl_sub_rule_set_validate(OTL_Bytes table,OTL_Validator valid)483   otl_sub_rule_set_validate( OTL_Bytes      table,
484                              OTL_Validator  valid )
485   {
486     OTL_Bytes  p = table;
487     OTL_UInt   count;
488 
489     OTL_CHECK( 2 );
490     count = OTL_NEXT_USHORT( p );
491 
492     OTL_CHECK( 2*count );
493     for ( ; count > 0; count-- )
494       otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
495   }
496 
497 
498   static void
otl_sub_class_rule_validate(OTL_Bytes table,OTL_Validator valid)499   otl_sub_class_rule_validate( OTL_Bytes      table,
500                                OTL_Validator  valid )
501   {
502     OTL_UInt  glyph_count, subst_count;
503 
504     OTL_CHECK( 4 );
505     glyph_count = OTL_NEXT_USHORT( p );
506     subst_count = OTL_NEXT_USHORT( p );
507 
508     if ( glyph_count == 0 )
509       OTL_INVALID_DATA;
510 
511     OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
512 
513     /* XXX: check glyph indices and subst lookups */
514   }
515 
516 
517   static void
otl_sub_class_rule_set_validate(OTL_Bytes table,OTL_Validator valid)518   otl_sub_class_rule_set_validate( OTL_Bytes      table,
519                                    OTL_Validator  valid )
520   {
521     OTL_Bytes  p = table;
522     OTL_UInt   count;
523 
524     OTL_CHECK( 2 );
525     count = OTL_NEXT_USHORT( p );
526 
527     OTL_CHECK( 2*count );
528     for ( ; count > 0; count-- )
529       otl_sub_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
530   }
531 
532 
533   static void
otl_gsub_lookup5_validate(OTL_Bytes table,OTL_Validator valid)534   otl_gsub_lookup5_validate( OTL_Bytes      table,
535                              OTL_Validator  valid )
536   {
537     OTL_Bytes  p = table;
538     OTL_UInt   format, coverage;
539 
540     OTL_CHECK( 2 );
541     format = OTL_NEXT_USHORT( p );
542     switch ( format )
543     {
544       case 1:
545         {
546           OTL_UInt  coverage, count;
547 
548           OTL_CHECK( 4 );
549           coverage = OTL_NEXT_USHORT( p );
550           count    = OTL_NEXT_USHORT( p );
551 
552           otl_coverage_validate( table + coverage, valid );
553 
554           OTL_CHECK( 2*count );
555           for ( ; count > 0; count-- )
556             otl_sub_rule_set_validate( table + coverage, valid );
557         }
558         break;
559 
560       case 2:
561         {
562           OTL_UInt  coverage, class_def, count;
563 
564           OTL_CHECK( 6 );
565           coverage  = OTL_NEXT_USHORT( p );
566           class_def = OTL_NEXT_USHORT( p );
567           count     = OTL_NEXT_USHORT( p );
568 
569           otl_coverage_validate        ( table + coverage, valid );
570           otl_class_definition_validate( table + class_def, valid );
571 
572           OTL_CHECK( 2*count );
573           for ( ; count > 0; count-- )
574             otl_sub_class_rule_set_validate( table + coveragen valid );
575         }
576         break;
577 
578       case 3:
579         {
580           OTL_UInt  glyph_count, subst_count, count;
581 
582           OTL_CHECK( 4 );
583           glyph_count = OTL_NEXT_USHORT( p );
584           subst_count = OTL_NEXT_USHORT( p );
585 
586           OTL_CHECK( 2*glyph_count + 4*subst_count );
587           for ( count = glyph_count; count > 0; count-- )
588             otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
589         }
590         break;
591 
592       default:
593         OTL_INVALID_DATA;
594     }
595   }
596 
597 
598  /************************************************************************/
599  /************************************************************************/
600  /*****                                                              *****/
601  /*****                 GSUB LOOKUP TYPE 6                           *****/
602  /*****                                                              *****/
603  /************************************************************************/
604  /************************************************************************/
605 
606 
607   static void
otl_chain_sub_rule_validate(OTL_Bytes table,OTL_Validator valid)608   otl_chain_sub_rule_validate( OTL_Bytes      table,
609                                OTL_Validator  valid )
610   {
611     OTL_Bytes  p = table;
612     OTL_UInt   back_count, input_count, ahead_count, subst_count, count;
613 
614     OTL_CHECK( 2 );
615     back_count = OTL_NEXT_USHORT( p );
616 
617     OTL_CHECK( 2*back_count+2 );
618     p += 2*back_count;
619 
620     input_count = OTL_NEXT_USHORT( p );
621     if ( input_count == 0 )
622       OTL_INVALID_DATA;
623 
624     OTL_CHECK( 2*input_count );
625     p += 2*(input_count-1);
626 
627     ahead_count = OTL_NEXT_USHORT( p );
628     OTL_CHECK( 2*ahead_count + 2 );
629     p += 2*ahead_count;
630 
631     count = OTL_NEXT_USHORT( p );
632     OTL_CHECK( 4*count );
633 
634     /* XXX: check glyph indices and subst lookups */
635   }
636 
637 
638   static void
otl_chain_sub_rule_set_validate(OTL_Bytes table,OTL_Validator valid)639   otl_chain_sub_rule_set_validate( OTL_Bytes      table,
640                                    OTL_Validator  valid )
641   {
642     OTL_Bytes  p = table;
643     OTL_UInt   count;
644 
645     OTL_CHECK( 2 );
646     count = OTL_NEXT_USHORT( p );
647 
648     OTL_CHECK( 2*count );
649     for ( ; count > 0; count-- )
650       otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
651   }
652 
653 
654   static void
otl_chain_sub_class_rule_validate(OTL_Bytes table,OTL_Validator valid)655   otl_chain_sub_class_rule_validate( OTL_Bytes      table,
656                                      OTL_Validator  valid )
657   {
658     OTL_Bytes  p = table;
659     OTL_UInt   back_count, input_count, ahead_count, subst_count, count;
660 
661     OTL_CHECK( 2 );
662     back_count = OTL_NEXT_USHORT( p );
663 
664     OTL_CHECK( 2*back_count+2 );
665     p += 2*back_count;
666 
667     input_count = OTL_NEXT_USHORT( p );
668     if ( input_count == 0 )
669       OTL_INVALID_DATA;
670 
671     OTL_CHECK( 2*input_count );
672     p += 2*(input_count-1);
673 
674     ahead_count = OTL_NEXT_USHORT( p );
675     OTL_CHECK( 2*ahead_count + 2 );
676     p += 2*ahead_count;
677 
678     count = OTL_NEXT_USHORT( p );
679     OTL_CHECK( 4*count );
680 
681     /* XXX: check class indices and subst lookups */
682   }
683 
684 
685 
686   static void
otl_chain_sub_class_set_validate(OTL_Bytes table,OTL_Validator valid)687   otl_chain_sub_class_set_validate( OTL_Bytes      table,
688                                     OTL_Validator  valid )
689   {
690     OTL_Bytes  p = table;
691     OTL_UInt   count;
692 
693     OTL_CHECK( 2 );
694     count = OTL_NEXT_USHORT( p );
695 
696     OTL_CHECK( 2*count );
697     for ( ; count > 0; count-- )
698       otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
699   }
700 
701 
702   static void
otl_gsub_lookup6_validate(OTL_Bytes table,OTL_Validator valid)703   otl_gsub_lookup6_validate( OTL_Bytes      table,
704                              OTL_Validator  valid )
705   {
706     OTL_Bytes  p = table;
707     OTL_UInt   format, coverage;
708 
709     OTL_CHECK( 2 );
710     format = OTL_NEXT_USHORT( p );
711     switch ( format )
712     {
713       case 1:
714         {
715           OTL_UInt  coverage, count;
716 
717           OTL_CHECK( 4 );
718           coverage = OTL_NEXT_USHORT( p );
719           count    = OTL_NEXT_USHORT( p );
720 
721           otl_coverage_validate( table + coverage, valid );
722 
723           OTL_CHECK( 2*count );
724           for ( ; count > 0; count-- )
725             otl_chain_sub_rule_set_validate( table + coverage, valid );
726         }
727         break;
728 
729       case 2:
730         {
731           OTL_UInt  coverage, back_class, input_class, ahead_class, count;
732 
733           OTL_CHECK( 10 );
734           coverage    = OTL_NEXT_USHORT( p );
735           back_class  = OTL_NEXT_USHORT( p );
736           input_class = OTL_NEXT_USHORT( p );
737           ahead_class = OTL_NEXT_USHORT( p );
738           count       = OTL_NEXT_USHORT( p );
739 
740           otl_coverage_validate( table + coverage, valid );
741 
742           otl_class_definition_validate( table + back_class,  valid );
743           otl_class_definition_validate( table + input_class, valid );
744           otl_class_definition_validate( table + ahead_class, valid );
745 
746           OTL_CHECK( 2*count );
747           for ( ; count > 0; count-- )
748             otl_chain_sub_class_set( table + OTL_NEXT_USHORT( p ), valid );
749         }
750         break;
751 
752       case 3:
753         {
754           OTL_UInt  back_count, input_count, ahead_count, subst_count, count;
755 
756           OTL_CHECK( 2 );
757           back_count = OTL_NEXT_USHORT( p );
758 
759           OTL_CHECK( 2*back_count+2 );
760           for ( count = back_count; count > 0; count-- )
761             otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
762 
763           input_count = OTL_NEXT_USHORT( p );
764 
765           OTL_CHECK( 2*input_count+2 );
766           for ( count = input_count; count > 0; count-- )
767             otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
768 
769           ahead_count = OTL_NEXT_USHORT( p );
770 
771           OTL_CHECK( 2*ahead_count+2 );
772           for ( count = ahead_count; count > 0; count-- )
773             otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
774 
775           subst_count = OTL_NEXT_USHORT( p );
776           OTL_CHECK( subst_count*4 );
777         }
778         break;
779 
780       default:
781         OTL_INVALID_DATA;
782     }
783   }
784 
785  /************************************************************************/
786  /************************************************************************/
787  /*****                                                              *****/
788  /*****                 GSUB LOOKUP TYPE 6                           *****/
789  /*****                                                              *****/
790  /************************************************************************/
791  /************************************************************************/
792 
793   static void
otl_gsub_lookup7_validate(OTL_Bytes table,OTL_Validator valid)794   otl_gsub_lookup7_validate( OTL_Bytes      table,
795                              OTL_Validator  valid )
796   {
797     OTL_Bytes  p = table;
798     OTL_UInt   format, coverage;
799 
800     OTL_CHECK( 2 );
801     format = OTL_NEXT_USHORT( p );
802     switch ( format )
803     {
804       case 1:
805         {
806           OTL_UInt          lookup_type, lookup_offset;
807           OTL_ValidateFunc  validate;
808 
809           OTL_CHECK( 6 );
810           lookup_type   = OTL_NEXT_USHORT( p );
811           lookup_offset = OTL_NEXT_ULONG( p );
812 
813           if ( lookup_type == 0 || lookup_type >= 7 )
814             OTL_INVALID_DATA;
815 
816           validate = otl_gsub_validate_funcs[ lookup_type-1 ];
817           validate( table + lookup_offset, valid );
818         }
819         break;
820 
821       default:
822         OTL_INVALID_DATA;
823     }
824   }
825 
826 
827   static const OTL_ValidateFunc  otl_gsub_validate_funcs[ 7 ] =
828   {
829     otl_gsub_lookup1_validate,
830     otl_gsub_lookup2_validate,
831     otl_gsub_lookup3_validate,
832     otl_gsub_lookup4_validate,
833     otl_gsub_lookup5_validate,
834     otl_gsub_lookup6_validate
835   };
836 
837  /************************************************************************/
838  /************************************************************************/
839  /*****                                                              *****/
840  /*****                         GSUB TABLE                           *****/
841  /*****                                                              *****/
842  /************************************************************************/
843  /************************************************************************/
844 
845 
846   OTL_LOCALDEF( void )
otl_gsub_validate(OTL_Bytes table,OTL_Validator valid)847   otl_gsub_validate( OTL_Bytes      table,
848                      OTL_Validator  valid )
849   {
850     OTL_Bytes  p = table;
851     OTL_UInt   scripts, features, lookups;
852 
853     OTL_CHECK( 10 );
854 
855     if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
856       OTL_INVALID_DATA;
857 
858     scripts  = OTL_NEXT_USHORT( p );
859     features = OTL_NEXT_USHORT( p );
860     lookups  = OTL_NEXT_USHORT( p );
861 
862     otl_script_list_validate ( table + scripts, valid );
863     otl_feature_list_validate( table + features, valid );
864 
865     otl_lookup_list_validate( table + lookups, 7, otl_gsub_validate_funcs,
866                               valid );
867   }
868