- Italian translation by Daniele Forsi (dforsi at gmail dot com)
[reactos.git] / reactos / dll / 3rdparty / freetype / src / otlayout / otlgsub.c
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
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
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 != 0xFFFFU && 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 ) & 0xFFFFU;
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
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
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
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 != 0xFFFFU && 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
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
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
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 != 0xFFFFU && 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 )
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 }