1/****************************************************************************
2 *
3 * otvgpos.c
4 *
5 * OpenType GPOS table validation (body).
6 *
7 * Copyright (C) 2002-2023 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
59 otv_x_sxy( FT_Bytes table,
60 OTV_Validator otvalid )
61 {
62 FT_Bytes p = table;
63 FT_UInt Count, count1, table_size;
64
65
66 OTV_ENTER;
67
68 OTV_LIMIT_CHECK( 2 );
69
70 Count = FT_NEXT_USHORT( p );
71
72 OTV_TRACE(( " (Count = %d)\n", Count ));
73
74 OTV_LIMIT_CHECK( Count * otvalid->extra1 * 2 );
75
76 table_size = Count * otvalid->extra1 * 2 + 2;
77
78 for ( ; Count > 0; Count-- )
79 for ( count1 = otvalid->extra1; count1 > 0; count1-- )
80 {
81 OTV_OPTIONAL_TABLE( anchor_offset );
82
83
84 OTV_OPTIONAL_OFFSET( anchor_offset );
85
86 if ( otvalid->extra2 )
87 {
88 OTV_SIZE_CHECK( anchor_offset );
89 if ( anchor_offset )
90 otv_Anchor_validate( table + anchor_offset, otvalid );
91 }
92 else
93 otv_Anchor_validate( table + anchor_offset, otvalid );
94 }
95
96 OTV_EXIT;
97 }
98
99
100#define MarkBasePosFormat1Func otv_u_O_O_u_O_O
101#define MarkLigPosFormat1Func otv_u_O_O_u_O_O
102#define MarkMarkPosFormat1Func otv_u_O_O_u_O_O
103
104 /* sets otvalid->extra1 (class count) */
105
106 static void
107 otv_u_O_O_u_O_O( FT_Bytes table,
108 OTV_Validator otvalid )
109 {
110 FT_Bytes p = table;
111 FT_UInt Coverage1, Coverage2, ClassCount;
112 FT_UInt Array1, Array2;
113 OTV_Validate_Func func;
114
115
116 OTV_ENTER;
117
118 p += 2; /* skip PosFormat */
119
120 OTV_LIMIT_CHECK( 10 );
121 Coverage1 = FT_NEXT_USHORT( p );
122 Coverage2 = FT_NEXT_USHORT( p );
123 ClassCount = FT_NEXT_USHORT( p );
124 Array1 = FT_NEXT_USHORT( p );
125 Array2 = FT_NEXT_USHORT( p );
126
127 otv_Coverage_validate( table + Coverage1, otvalid, -1 );
128 otv_Coverage_validate( table + Coverage2, otvalid, -1 );
129
130 otv_MarkArray_validate( table + Array1, otvalid );
131
132 otvalid->nesting_level++;
133 func = otvalid->func[otvalid->nesting_level];
134 otvalid->extra1 = ClassCount;
135
136 func( table + Array2, otvalid );
137
138 otvalid->nesting_level--;
139
140 OTV_EXIT;
141 }
142
143
144 /*************************************************************************/
145 /*************************************************************************/
146 /***** *****/
147 /***** VALUE RECORDS *****/
148 /***** *****/
149 /*************************************************************************/
150 /*************************************************************************/
151
152 static FT_UInt
153 otv_value_length( FT_UInt format )
154 {
155 FT_UInt count;
156
157
158 count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 );
159 count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 );
160 count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F );
161
162 return count * 2;
163 }
164
165
166 /* uses otvalid->extra3 (pointer to base table) */
167
168 static void
169 otv_ValueRecord_validate( FT_Bytes table,
170 FT_UInt format,
171 OTV_Validator otvalid )
172 {
173 FT_Bytes p = table;
174 FT_UInt count;
175
176#ifdef FT_DEBUG_LEVEL_TRACE
177 FT_Int loop;
178 FT_ULong res = 0;
179
180
181 OTV_NAME_ENTER( "ValueRecord" );
182
183 /* display `format' in dual representation */
184 for ( loop = 7; loop >= 0; loop-- )
185 {
186 res <<= 4;
187 res += ( format >> loop ) & 1;
188 }
189
190 OTV_TRACE(( " (format 0b%08lx)\n", res ));
191#endif
192
193 if ( format >= 0x100 )
194 FT_INVALID_FORMAT;
195
196 for ( count = 4; count > 0; count-- )
197 {
198 if ( format & 1 )
199 {
200 /* XPlacement, YPlacement, XAdvance, YAdvance */
201 OTV_LIMIT_CHECK( 2 );
202 p += 2;
203 }
204
205 format >>= 1;
206 }
207
208 for ( count = 4; count > 0; count-- )
209 {
210 if ( format & 1 )
211 {
212 FT_PtrDist table_size;
213
214 OTV_OPTIONAL_TABLE( device );
215
216
217 /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */
218 OTV_LIMIT_CHECK( 2 );
219 OTV_OPTIONAL_OFFSET( device );
220
221 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
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
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
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
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
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
579 otv_CursivePos_validate( FT_Bytes table,
580 OTV_Validator otvalid )
581 {
582 FT_Bytes p = table;
583 FT_UInt PosFormat;
584
585
586 OTV_NAME_ENTER( "CursivePos" );
587
588 OTV_LIMIT_CHECK( 2 );
589 PosFormat = FT_NEXT_USHORT( p );
590
591 OTV_TRACE(( " (format %d)\n", PosFormat ));
592
593 switch ( PosFormat )
594 {
595 case 1: /* CursivePosFormat1 */
596 {
597 FT_UInt table_size;
598 FT_UInt Coverage, EntryExitCount;
599
600 OTV_OPTIONAL_TABLE( EntryAnchor );
601 OTV_OPTIONAL_TABLE( ExitAnchor );
602
603
604 OTV_LIMIT_CHECK( 4 );
605 Coverage = FT_NEXT_USHORT( p );
606 EntryExitCount = FT_NEXT_USHORT( p );
607
608 OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
609
610 otv_Coverage_validate( table + Coverage,
611 otvalid,
612 (FT_Int)EntryExitCount );
613
614 OTV_LIMIT_CHECK( EntryExitCount * 4 );
615
616 table_size = EntryExitCount * 4 + 4;
617
618 /* EntryExitRecord */
619 for ( ; EntryExitCount > 0; EntryExitCount-- )
620 {
621 OTV_OPTIONAL_OFFSET( EntryAnchor );
622 OTV_OPTIONAL_OFFSET( ExitAnchor );
623
624 OTV_SIZE_CHECK( EntryAnchor );
625 if ( EntryAnchor )
626 otv_Anchor_validate( table + EntryAnchor, otvalid );
627
628 OTV_SIZE_CHECK( ExitAnchor );
629 if ( ExitAnchor )
630 otv_Anchor_validate( table + ExitAnchor, otvalid );
631 }
632 }
633 break;
634
635 default:
636 FT_INVALID_FORMAT;
637 }
638
639 OTV_EXIT;
640 }
641
642
643 /*************************************************************************/
644 /*************************************************************************/
645 /***** *****/
646 /***** GPOS LOOKUP TYPE 4 *****/
647 /***** *****/
648 /*************************************************************************/
649 /*************************************************************************/
650
651 /* UNDOCUMENTED (in OpenType 1.5): */
652 /* BaseRecord tables can contain NULL pointers. */
653
654 /* sets otvalid->extra2 (1) */
655
656 static void
657 otv_MarkBasePos_validate( FT_Bytes table,
658 OTV_Validator otvalid )
659 {
660 FT_Bytes p = table;
661 FT_UInt PosFormat;
662
663
664 OTV_NAME_ENTER( "MarkBasePos" );
665
666 OTV_LIMIT_CHECK( 2 );
667 PosFormat = FT_NEXT_USHORT( p );
668
669 OTV_TRACE(( " (format %d)\n", PosFormat ));
670
671 switch ( PosFormat )
672 {
673 case 1:
674 otvalid->extra2 = 1;
675 OTV_NEST2( MarkBasePosFormat1, BaseArray );
676 OTV_RUN( table, otvalid );
677 break;
678
679 default:
680 FT_INVALID_FORMAT;
681 }
682
683 OTV_EXIT;
684 }
685
686
687 /*************************************************************************/
688 /*************************************************************************/
689 /***** *****/
690 /***** GPOS LOOKUP TYPE 5 *****/
691 /***** *****/
692 /*************************************************************************/
693 /*************************************************************************/
694
695 /* sets otvalid->extra2 (1) */
696
697 static void
698 otv_MarkLigPos_validate( FT_Bytes table,
699 OTV_Validator otvalid )
700 {
701 FT_Bytes p = table;
702 FT_UInt PosFormat;
703
704
705 OTV_NAME_ENTER( "MarkLigPos" );
706
707 OTV_LIMIT_CHECK( 2 );
708 PosFormat = FT_NEXT_USHORT( p );
709
710 OTV_TRACE(( " (format %d)\n", PosFormat ));
711
712 switch ( PosFormat )
713 {
714 case 1:
715 otvalid->extra2 = 1;
716 OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
717 OTV_RUN( table, otvalid );
718 break;
719
720 default:
721 FT_INVALID_FORMAT;
722 }
723
724 OTV_EXIT;
725 }
726
727
728 /*************************************************************************/
729 /*************************************************************************/
730 /***** *****/
731 /***** GPOS LOOKUP TYPE 6 *****/
732 /***** *****/
733 /*************************************************************************/
734 /*************************************************************************/
735
736 /* sets otvalid->extra2 (0) */
737
738 static void
739 otv_MarkMarkPos_validate( FT_Bytes table,
740 OTV_Validator otvalid )
741 {
742 FT_Bytes p = table;
743 FT_UInt PosFormat;
744
745
746 OTV_NAME_ENTER( "MarkMarkPos" );
747
748 OTV_LIMIT_CHECK( 2 );
749 PosFormat = FT_NEXT_USHORT( p );
750
751 OTV_TRACE(( " (format %d)\n", PosFormat ));
752
753 switch ( PosFormat )
754 {
755 case 1:
756 otvalid->extra2 = 0;
757 OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
758 OTV_RUN( table, otvalid );
759 break;
760
761 default:
762 FT_INVALID_FORMAT;
763 }
764
765 OTV_EXIT;
766 }
767
768
769 /*************************************************************************/
770 /*************************************************************************/
771 /***** *****/
772 /***** GPOS LOOKUP TYPE 7 *****/
773 /***** *****/
774 /*************************************************************************/
775 /*************************************************************************/
776
777 /* sets otvalid->extra1 (lookup count) */
778
779 static void
780 otv_ContextPos_validate( FT_Bytes table,
781 OTV_Validator otvalid )
782 {
783 FT_Bytes p = table;
784 FT_UInt PosFormat;
785
786
787 OTV_NAME_ENTER( "ContextPos" );
788
789 OTV_LIMIT_CHECK( 2 );
790 PosFormat = FT_NEXT_USHORT( p );
791
792 OTV_TRACE(( " (format %d)\n", PosFormat ));
793
794 switch ( PosFormat )
795 {
796 case 1:
797 /* no need to check glyph indices/classes used as input for these */
798 /* context rules since even invalid glyph indices/classes return */
799 /* meaningful results */
800
801 otvalid->extra1 = otvalid->lookup_count;
802 OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
803 OTV_RUN( table, otvalid );
804 break;
805
806 case 2:
807 /* no need to check glyph indices/classes used as input for these */
808 /* context rules since even invalid glyph indices/classes return */
809 /* meaningful results */
810
811 OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
812 OTV_RUN( table, otvalid );
813 break;
814
815 case 3:
816 OTV_NEST1( ContextPosFormat3 );
817 OTV_RUN( table, otvalid );
818 break;
819
820 default:
821 FT_INVALID_FORMAT;
822 }
823
824 OTV_EXIT;
825 }
826
827
828 /*************************************************************************/
829 /*************************************************************************/
830 /***** *****/
831 /***** GPOS LOOKUP TYPE 8 *****/
832 /***** *****/
833 /*************************************************************************/
834 /*************************************************************************/
835
836 /* sets otvalid->extra1 (lookup count) */
837
838 static void
839 otv_ChainContextPos_validate( FT_Bytes table,
840 OTV_Validator otvalid )
841 {
842 FT_Bytes p = table;
843 FT_UInt PosFormat;
844
845
846 OTV_NAME_ENTER( "ChainContextPos" );
847
848 OTV_LIMIT_CHECK( 2 );
849 PosFormat = FT_NEXT_USHORT( p );
850
851 OTV_TRACE(( " (format %d)\n", PosFormat ));
852
853 switch ( PosFormat )
854 {
855 case 1:
856 /* no need to check glyph indices/classes used as input for these */
857 /* context rules since even invalid glyph indices/classes return */
858 /* meaningful results */
859
860 otvalid->extra1 = otvalid->lookup_count;
861 OTV_NEST3( ChainContextPosFormat1,
862 ChainPosRuleSet, ChainPosRule );
863 OTV_RUN( table, otvalid );
864 break;
865
866 case 2:
867 /* no need to check glyph indices/classes used as input for these */
868 /* context rules since even invalid glyph indices/classes return */
869 /* meaningful results */
870
871 OTV_NEST3( ChainContextPosFormat2,
872 ChainPosClassSet, ChainPosClassRule );
873 OTV_RUN( table, otvalid );
874 break;
875
876 case 3:
877 OTV_NEST1( ChainContextPosFormat3 );
878 OTV_RUN( table, otvalid );
879 break;
880
881 default:
882 FT_INVALID_FORMAT;
883 }
884
885 OTV_EXIT;
886 }
887
888
889 /*************************************************************************/
890 /*************************************************************************/
891 /***** *****/
892 /***** GPOS LOOKUP TYPE 9 *****/
893 /***** *****/
894 /*************************************************************************/
895 /*************************************************************************/
896
897 /* uses otvalid->type_funcs */
898
899 static void
900 otv_ExtensionPos_validate( FT_Bytes table,
901 OTV_Validator otvalid )
902 {
903 FT_Bytes p = table;
904 FT_UInt PosFormat;
905
906
907 OTV_NAME_ENTER( "ExtensionPos" );
908
909 OTV_LIMIT_CHECK( 2 );
910 PosFormat = FT_NEXT_USHORT( p );
911
912 OTV_TRACE(( " (format %d)\n", PosFormat ));
913
914 switch ( PosFormat )
915 {
916 case 1: /* ExtensionPosFormat1 */
917 {
918 FT_UInt ExtensionLookupType;
919 FT_ULong ExtensionOffset;
920 OTV_Validate_Func validate;
921
922
923 OTV_LIMIT_CHECK( 6 );
924 ExtensionLookupType = FT_NEXT_USHORT( p );
925 ExtensionOffset = FT_NEXT_ULONG( p );
926
927 if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
928 FT_INVALID_DATA;
929
930 validate = otvalid->type_funcs[ExtensionLookupType - 1];
931 validate( table + ExtensionOffset, otvalid );
932 }
933 break;
934
935 default:
936 FT_INVALID_FORMAT;
937 }
938
939 OTV_EXIT;
940 }
941
942
943 static const OTV_Validate_Func otv_gpos_validate_funcs[9] =
944 {
945 otv_SinglePos_validate,
946 otv_PairPos_validate,
947 otv_CursivePos_validate,
948 otv_MarkBasePos_validate,
949 otv_MarkLigPos_validate,
950 otv_MarkMarkPos_validate,
951 otv_ContextPos_validate,
952 otv_ChainContextPos_validate,
953 otv_ExtensionPos_validate
954 };
955
956
957 /* sets otvalid->type_count */
958 /* sets otvalid->type_funcs */
959
960 FT_LOCAL_DEF( void )
961 otv_GPOS_subtable_validate( FT_Bytes table,
962 OTV_Validator otvalid )
963 {
964 otvalid->type_count = 9;
965 otvalid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs;
966
967 otv_Lookup_validate( table, otvalid );
968 }
969
970
971 /*************************************************************************/
972 /*************************************************************************/
973 /***** *****/
974 /***** GPOS TABLE *****/
975 /***** *****/
976 /*************************************************************************/
977 /*************************************************************************/
978
979 /* sets otvalid->glyph_count */
980
981 FT_LOCAL_DEF( void )
982 otv_GPOS_validate( FT_Bytes table,
983 FT_UInt glyph_count,
984 FT_Validator ftvalid )
985 {
986 OTV_ValidatorRec validrec;
987 OTV_Validator otvalid = &validrec;
988 FT_Bytes p = table;
989 FT_UInt 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