2137db842a41e77298782919ce48deab3d12e647
[reactos.git] / lib / 3rdparty / freetype / src / gxvalid / gxvkern.c
1 /***************************************************************************/
2 /* */
3 /* gxvkern.c */
4 /* */
5 /* TrueTypeGX/AAT kern table validation (body). */
6 /* */
7 /* Copyright 2004, 2005, 2006, 2007 */
8 /* by suzuki toshiya, Masatake YAMATO, Red Hat K.K., */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
16 /* */
17 /***************************************************************************/
18
19 /***************************************************************************/
20 /* */
21 /* gxvalid is derived from both gxlayout module and otvalid module. */
22 /* Development of gxlayout is supported by the Information-technology */
23 /* Promotion Agency(IPA), Japan. */
24 /* */
25 /***************************************************************************/
26
27
28 #include "gxvalid.h"
29 #include "gxvcommn.h"
30
31 #include FT_SFNT_NAMES_H
32 #include FT_SERVICE_GX_VALIDATE_H
33
34
35 /*************************************************************************/
36 /* */
37 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
38 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
39 /* messages during execution. */
40 /* */
41 #undef FT_COMPONENT
42 #define FT_COMPONENT trace_gxvkern
43
44
45 /*************************************************************************/
46 /*************************************************************************/
47 /***** *****/
48 /***** Data and Types *****/
49 /***** *****/
50 /*************************************************************************/
51 /*************************************************************************/
52
53 typedef enum GXV_kern_Version_
54 {
55 KERN_VERSION_CLASSIC = 0x0000,
56 KERN_VERSION_NEW = 0x0001
57
58 } GXV_kern_Version;
59
60
61 typedef enum GXV_kern_Dialect_
62 {
63 KERN_DIALECT_UNKNOWN = 0,
64 KERN_DIALECT_MS = FT_VALIDATE_MS,
65 KERN_DIALECT_APPLE = FT_VALIDATE_APPLE,
66 KERN_DIALECT_ANY = FT_VALIDATE_CKERN
67
68 } GXV_kern_Dialect;
69
70
71 typedef struct GXV_kern_DataRec_
72 {
73 GXV_kern_Version version;
74 void *subtable_data;
75 GXV_kern_Dialect dialect_request;
76
77 } GXV_kern_DataRec, *GXV_kern_Data;
78
79
80 #define GXV_KERN_DATA( field ) GXV_TABLE_DATA( kern, field )
81
82 #define KERN_IS_CLASSIC( valid ) \
83 ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) )
84 #define KERN_IS_NEW( valid ) \
85 ( KERN_VERSION_NEW == GXV_KERN_DATA( version ) )
86
87 #define KERN_DIALECT( valid ) \
88 GXV_KERN_DATA( dialect_request )
89 #define KERN_ALLOWS_MS( valid ) \
90 ( KERN_DIALECT( valid ) & KERN_DIALECT_MS )
91 #define KERN_ALLOWS_APPLE( valid ) \
92 ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE )
93
94 #define GXV_KERN_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 4 )
95 #define GXV_KERN_SUBTABLE_HEADER_SIZE ( KERN_IS_NEW( valid ) ? 8 : 6 )
96
97
98 /*************************************************************************/
99 /*************************************************************************/
100 /***** *****/
101 /***** SUBTABLE VALIDATORS *****/
102 /***** *****/
103 /*************************************************************************/
104 /*************************************************************************/
105
106
107 /* ============================= format 0 ============================== */
108
109 static void
110 gxv_kern_subtable_fmt0_pairs_validate( FT_Bytes table,
111 FT_Bytes limit,
112 FT_UShort nPairs,
113 GXV_Validator valid )
114 {
115 FT_Bytes p = table;
116 FT_UShort i;
117
118 FT_UShort last_gid_left = 0;
119 FT_UShort last_gid_right = 0;
120
121 FT_UNUSED( limit );
122
123
124 GXV_NAME_ENTER( "kern format 0 pairs" );
125
126 for ( i = 0; i < nPairs; i++ )
127 {
128 FT_UShort gid_left;
129 FT_UShort gid_right;
130 FT_Short kernValue;
131
132
133 /* left */
134 gid_left = FT_NEXT_USHORT( p );
135 gxv_glyphid_validate( gid_left, valid );
136
137 /* right */
138 gid_right = FT_NEXT_USHORT( p );
139 gxv_glyphid_validate( gid_right, valid );
140
141 /* Pairs of left and right GIDs must be unique and sorted. */
142 GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right ));
143 if ( gid_left == last_gid_left )
144 {
145 if ( last_gid_right < gid_right )
146 last_gid_right = gid_right;
147 else
148 FT_INVALID_DATA;
149 }
150 else if ( last_gid_left < gid_left )
151 {
152 last_gid_left = gid_left;
153 last_gid_right = gid_right;
154 }
155 else
156 FT_INVALID_DATA;
157
158 /* skip the kern value */
159 kernValue = FT_NEXT_SHORT( p );
160 }
161
162 GXV_EXIT;
163 }
164
165 static void
166 gxv_kern_subtable_fmt0_validate( FT_Bytes table,
167 FT_Bytes limit,
168 GXV_Validator valid )
169 {
170 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
171
172 FT_UShort nPairs;
173 FT_UShort unitSize;
174
175
176 GXV_NAME_ENTER( "kern subtable format 0" );
177
178 unitSize = 2 + 2 + 2;
179 nPairs = 0;
180
181 /* nPairs, searchRange, entrySelector, rangeShift */
182 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
183 gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, valid );
184 p += 2 + 2 + 2 + 2;
185
186 gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, valid );
187
188 GXV_EXIT;
189 }
190
191
192 /* ============================= format 1 ============================== */
193
194
195 typedef struct GXV_kern_fmt1_StateOptRec_
196 {
197 FT_UShort valueTable;
198 FT_UShort valueTable_length;
199
200 } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData;
201
202
203 static void
204 gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes table,
205 FT_Bytes limit,
206 GXV_Validator valid )
207 {
208 FT_Bytes p = table;
209 GXV_kern_fmt1_StateOptRecData optdata =
210 (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
211
212
213 GXV_LIMIT_CHECK( 2 );
214 optdata->valueTable = FT_NEXT_USHORT( p );
215 }
216
217
218 /*
219 * passed tables_size covers whole StateTable, including kern fmt1 header
220 */
221 static void
222 gxv_kern_subtable_fmt1_subtable_setup( FT_UShort table_size,
223 FT_UShort classTable,
224 FT_UShort stateArray,
225 FT_UShort entryTable,
226 FT_UShort* classTable_length_p,
227 FT_UShort* stateArray_length_p,
228 FT_UShort* entryTable_length_p,
229 GXV_Validator valid )
230 {
231 FT_UShort o[4];
232 FT_UShort *l[4];
233 FT_UShort buff[5];
234
235 GXV_kern_fmt1_StateOptRecData optdata =
236 (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
237
238
239 o[0] = classTable;
240 o[1] = stateArray;
241 o[2] = entryTable;
242 o[3] = optdata->valueTable;
243 l[0] = classTable_length_p;
244 l[1] = stateArray_length_p;
245 l[2] = entryTable_length_p;
246 l[3] = &(optdata->valueTable_length);
247
248 gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid );
249 }
250
251
252 /*
253 * passed table & limit are of whole StateTable, not including subtables
254 */
255 static void
256 gxv_kern_subtable_fmt1_entry_validate(
257 FT_Byte state,
258 FT_UShort flags,
259 GXV_StateTable_GlyphOffsetCPtr glyphOffset_p,
260 FT_Bytes table,
261 FT_Bytes limit,
262 GXV_Validator valid )
263 {
264 FT_UShort push;
265 FT_UShort dontAdvance;
266 FT_UShort valueOffset;
267 FT_UShort kernAction;
268 FT_UShort kernValue;
269
270 FT_UNUSED( state );
271 FT_UNUSED( glyphOffset_p );
272
273
274 push = (FT_UShort)( ( flags >> 15 ) & 1 );
275 dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 );
276 valueOffset = (FT_UShort)( flags & 0x3FFF );
277
278 {
279 GXV_kern_fmt1_StateOptRecData vt_rec =
280 (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
281 FT_Bytes p;
282
283
284 if ( valueOffset < vt_rec->valueTable )
285 FT_INVALID_OFFSET;
286
287 p = table + valueOffset;
288 limit = table + vt_rec->valueTable + vt_rec->valueTable_length;
289
290 GXV_LIMIT_CHECK( 2 + 2 );
291 kernAction = FT_NEXT_USHORT( p );
292 kernValue = FT_NEXT_USHORT( p );
293 }
294 }
295
296
297 static void
298 gxv_kern_subtable_fmt1_validate( FT_Bytes table,
299 FT_Bytes limit,
300 GXV_Validator valid )
301 {
302 FT_Bytes p = table;
303 GXV_kern_fmt1_StateOptRec vt_rec;
304
305
306 GXV_NAME_ENTER( "kern subtable format 1" );
307
308 valid->statetable.optdata =
309 &vt_rec;
310 valid->statetable.optdata_load_func =
311 gxv_kern_subtable_fmt1_valueTable_load;
312 valid->statetable.subtable_setup_func =
313 gxv_kern_subtable_fmt1_subtable_setup;
314 valid->statetable.entry_glyphoffset_fmt =
315 GXV_GLYPHOFFSET_NONE;
316 valid->statetable.entry_validate_func =
317 gxv_kern_subtable_fmt1_entry_validate;
318
319 gxv_StateTable_validate( p, limit, valid );
320
321 GXV_EXIT;
322 }
323
324
325 /* ================ Data for Class-Based Subtables 2, 3 ================ */
326
327 typedef enum GXV_kern_ClassSpec_
328 {
329 GXV_KERN_CLS_L = 0,
330 GXV_KERN_CLS_R
331
332 } GXV_kern_ClassSpec;
333
334
335 /* ============================= format 2 ============================== */
336
337 /* ---------------------- format 2 specific data ----------------------- */
338
339 typedef struct GXV_kern_subtable_fmt2_DataRec_
340 {
341 FT_UShort rowWidth;
342 FT_UShort array;
343 FT_UShort offset_min[2];
344 FT_UShort offset_max[2];
345 const FT_String* class_tag[2];
346 GXV_odtect_Range odtect;
347
348 } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data;
349
350
351 #define GXV_KERN_FMT2_DATA( field ) \
352 ( ( (GXV_kern_subtable_fmt2_DataRec *) \
353 ( GXV_KERN_DATA( subtable_data ) ) )->field )
354
355
356 /* -------------------------- utility functions ----------------------- */
357
358 static void
359 gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes table,
360 FT_Bytes limit,
361 GXV_kern_ClassSpec spec,
362 GXV_Validator valid )
363 {
364 const FT_String* tag = GXV_KERN_FMT2_DATA( class_tag[spec] );
365 GXV_odtect_Range odtect = GXV_KERN_FMT2_DATA( odtect );
366
367 FT_Bytes p = table;
368 FT_UShort firstGlyph;
369 FT_UShort nGlyphs;
370
371
372 GXV_NAME_ENTER( "kern format 2 classTable" );
373
374 GXV_LIMIT_CHECK( 2 + 2 );
375 firstGlyph = FT_NEXT_USHORT( p );
376 nGlyphs = FT_NEXT_USHORT( p );
377 GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n",
378 tag, firstGlyph, nGlyphs ));
379
380 gxv_glyphid_validate( firstGlyph, valid );
381 gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), valid );
382
383 gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ),
384 &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ),
385 &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ),
386 valid );
387
388 gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect );
389
390 GXV_EXIT;
391 }
392
393
394 static void
395 gxv_kern_subtable_fmt2_validate( FT_Bytes table,
396 FT_Bytes limit,
397 GXV_Validator valid )
398 {
399 GXV_ODTECT( 3, odtect );
400 GXV_kern_subtable_fmt2_DataRec fmt2_rec =
401 { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL };
402
403 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
404 FT_UShort leftOffsetTable;
405 FT_UShort rightOffsetTable;
406
407
408 GXV_NAME_ENTER( "kern subtable format 2" );
409
410 GXV_ODTECT_INIT( odtect );
411 fmt2_rec.odtect = odtect;
412 GXV_KERN_DATA( subtable_data ) = &fmt2_rec;
413
414 GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
415 GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p );
416 leftOffsetTable = FT_NEXT_USHORT( p );
417 rightOffsetTable = FT_NEXT_USHORT( p );
418 GXV_KERN_FMT2_DATA( array ) = FT_NEXT_USHORT( p );
419
420 GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) ));
421
422
423 GXV_LIMIT_CHECK( leftOffsetTable );
424 GXV_LIMIT_CHECK( rightOffsetTable );
425 GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) );
426
427 gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit,
428 GXV_KERN_CLS_L, valid );
429
430 gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit,
431 GXV_KERN_CLS_R, valid );
432
433 if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) +
434 GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] )
435 < GXV_KERN_FMT2_DATA( array ) )
436 FT_INVALID_OFFSET;
437
438 gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ),
439 GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] )
440 + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] )
441 - GXV_KERN_FMT2_DATA( array ),
442 "array", odtect );
443
444 gxv_odtect_validate( odtect, valid );
445
446 GXV_EXIT;
447 }
448
449
450 /* ============================= format 3 ============================== */
451
452 static void
453 gxv_kern_subtable_fmt3_validate( FT_Bytes table,
454 FT_Bytes limit,
455 GXV_Validator valid )
456 {
457 FT_Bytes p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
458 FT_UShort glyphCount;
459 FT_Byte kernValueCount;
460 FT_Byte leftClassCount;
461 FT_Byte rightClassCount;
462 FT_Byte flags;
463
464
465 GXV_NAME_ENTER( "kern subtable format 3" );
466
467 GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 );
468 glyphCount = FT_NEXT_USHORT( p );
469 kernValueCount = FT_NEXT_BYTE( p );
470 leftClassCount = FT_NEXT_BYTE( p );
471 rightClassCount = FT_NEXT_BYTE( p );
472 flags = FT_NEXT_BYTE( p );
473
474 if ( valid->face->num_glyphs != glyphCount )
475 {
476 GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n",
477 valid->face->num_glyphs, glyphCount ));
478 if ( valid->root->level >= FT_VALIDATE_PARANOID )
479 FT_INVALID_GLYPH_ID;
480 }
481
482 /*
483 * just skip kernValue[kernValueCount]
484 */
485 GXV_LIMIT_CHECK( 2 * kernValueCount );
486 p += 2 * kernValueCount;
487
488 /*
489 * check leftClass[gid] < leftClassCount
490 */
491 {
492 FT_Byte min, max;
493
494
495 GXV_LIMIT_CHECK( glyphCount );
496 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
497 p += valid->subtable_length;
498
499 if ( leftClassCount < max )
500 FT_INVALID_DATA;
501 }
502
503 /*
504 * check rightClass[gid] < rightClassCount
505 */
506 {
507 FT_Byte min, max;
508
509
510 GXV_LIMIT_CHECK( glyphCount );
511 gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
512 p += valid->subtable_length;
513
514 if ( rightClassCount < max )
515 FT_INVALID_DATA;
516 }
517
518 /*
519 * check kernIndex[i, j] < kernValueCount
520 */
521 {
522 FT_UShort i, j;
523
524
525 for ( i = 0; i < leftClassCount; i++ )
526 {
527 for ( j = 0; j < rightClassCount; j++ )
528 {
529 GXV_LIMIT_CHECK( 1 );
530 if ( kernValueCount < FT_NEXT_BYTE( p ) )
531 FT_INVALID_OFFSET;
532 }
533 }
534 }
535
536 valid->subtable_length = p - table;
537
538 GXV_EXIT;
539 }
540
541
542 static FT_Bool
543 gxv_kern_coverage_new_apple_validate( FT_UShort coverage,
544 FT_UShort* format,
545 GXV_Validator valid )
546 {
547 /* new Apple-dialect */
548 FT_Bool kernVertical;
549 FT_Bool kernCrossStream;
550 FT_Bool kernVariation;
551
552 FT_UNUSED( valid );
553
554
555 /* reserved bits = 0 */
556 if ( coverage & 0x1FFC )
557 return 0;
558
559 kernVertical = FT_BOOL( ( coverage >> 15 ) & 1 );
560 kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 );
561 kernVariation = FT_BOOL( ( coverage >> 13 ) & 1 );
562
563 *format = (FT_UShort)( coverage & 0x0003 );
564
565 GXV_TRACE(( "new Apple-dialect: "
566 "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n",
567 !kernVertical, kernCrossStream, kernVariation, *format ));
568
569 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
570
571 return 1;
572 }
573
574
575 static FT_Bool
576 gxv_kern_coverage_classic_apple_validate( FT_UShort coverage,
577 FT_UShort* format,
578 GXV_Validator valid )
579 {
580 /* classic Apple-dialect */
581 FT_Bool horizontal;
582 FT_Bool cross_stream;
583
584
585 /* check expected flags, but don't check if MS-dialect is impossible */
586 if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) )
587 return 0;
588
589 /* reserved bits = 0 */
590 if ( coverage & 0x02FC )
591 return 0;
592
593 horizontal = FT_BOOL( ( coverage >> 15 ) & 1 );
594 cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 );
595
596 *format = (FT_UShort)( coverage & 0x0003 );
597
598 GXV_TRACE(( "classic Apple-dialect: "
599 "horizontal=%d, cross-stream=%d, format=%d\n",
600 horizontal, cross_stream, *format ));
601
602 /* format 1 requires GX State Machine, too new for classic */
603 if ( *format == 1 )
604 return 0;
605
606 GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
607
608 return 1;
609 }
610
611
612 static FT_Bool
613 gxv_kern_coverage_classic_microsoft_validate( FT_UShort coverage,
614 FT_UShort* format,
615 GXV_Validator valid )
616 {
617 /* classic Microsoft-dialect */
618 FT_Bool horizontal;
619 FT_Bool minimum;
620 FT_Bool cross_stream;
621 FT_Bool override;
622
623 FT_UNUSED( valid );
624
625
626 /* reserved bits = 0 */
627 if ( coverage & 0xFDF0 )
628 return 0;
629
630 horizontal = FT_BOOL( coverage & 1 );
631 minimum = FT_BOOL( ( coverage >> 1 ) & 1 );
632 cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 );
633 override = FT_BOOL( ( coverage >> 3 ) & 1 );
634
635 *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 );
636
637 GXV_TRACE(( "classic Microsoft-dialect: "
638 "horizontal=%d, minimum=%d, cross-stream=%d, "
639 "override=%d, format=%d\n",
640 horizontal, minimum, cross_stream, override, *format ));
641
642 if ( *format == 2 )
643 GXV_TRACE((
644 "kerning values in Microsoft format 2 subtable are ignored\n" ));
645
646 return 1;
647 }
648
649
650 /*************************************************************************/
651 /*************************************************************************/
652 /***** *****/
653 /***** MAIN *****/
654 /***** *****/
655 /*************************************************************************/
656 /*************************************************************************/
657
658 static GXV_kern_Dialect
659 gxv_kern_coverage_validate( FT_UShort coverage,
660 FT_UShort* format,
661 GXV_Validator valid )
662 {
663 GXV_kern_Dialect result = KERN_DIALECT_UNKNOWN;
664
665
666 GXV_NAME_ENTER( "validating coverage" );
667
668 GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage ));
669
670 if ( KERN_IS_NEW( valid ) )
671 {
672 if ( gxv_kern_coverage_new_apple_validate( coverage,
673 format,
674 valid ) )
675 {
676 result = KERN_DIALECT_APPLE;
677 goto Exit;
678 }
679 }
680
681 if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) )
682 {
683 if ( gxv_kern_coverage_classic_apple_validate( coverage,
684 format,
685 valid ) )
686 {
687 result = KERN_DIALECT_APPLE;
688 goto Exit;
689 }
690 }
691
692 if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) )
693 {
694 if ( gxv_kern_coverage_classic_microsoft_validate( coverage,
695 format,
696 valid ) )
697 {
698 result = KERN_DIALECT_MS;
699 goto Exit;
700 }
701 }
702
703 GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" ));
704
705 Exit:
706 GXV_EXIT;
707 return result;
708 }
709
710
711 static void
712 gxv_kern_subtable_validate( FT_Bytes table,
713 FT_Bytes limit,
714 GXV_Validator valid )
715 {
716 FT_Bytes p = table;
717 FT_UShort version = 0; /* MS only: subtable version, unused */
718 FT_ULong length; /* MS: 16bit, Apple: 32bit*/
719 FT_UShort coverage;
720 FT_UShort tupleIndex = 0; /* Apple only */
721 FT_UShort u16[2];
722 FT_UShort format = 255; /* subtable format */
723
724
725 GXV_NAME_ENTER( "kern subtable" );
726
727 GXV_LIMIT_CHECK( 2 + 2 + 2 );
728 u16[0] = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */
729 u16[1] = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */
730 coverage = FT_NEXT_USHORT( p );
731
732 switch ( gxv_kern_coverage_validate( coverage, &format, valid ) )
733 {
734 case KERN_DIALECT_MS:
735 version = u16[0];
736 length = u16[1];
737 tupleIndex = 0;
738 GXV_TRACE(( "Subtable version = %d\n", version ));
739 GXV_TRACE(( "Subtable length = %d\n", length ));
740 break;
741
742 case KERN_DIALECT_APPLE:
743 version = 0;
744 length = ( u16[0] << 16 ) + u16[1];
745 tupleIndex = 0;
746 GXV_TRACE(( "Subtable length = %d\n", length ));
747
748 if ( KERN_IS_NEW( valid ) )
749 {
750 GXV_LIMIT_CHECK( 2 );
751 tupleIndex = FT_NEXT_USHORT( p );
752 GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex ));
753 }
754 break;
755
756 default:
757 length = u16[1];
758 GXV_TRACE(( "cannot detect subtable dialect, "
759 "just skip %d byte\n", length ));
760 goto Exit;
761 }
762
763 /* formats 1, 2, 3 require the position of the start of this subtable */
764 if ( format == 0 )
765 gxv_kern_subtable_fmt0_validate( table, table + length, valid );
766 else if ( format == 1 )
767 gxv_kern_subtable_fmt1_validate( table, table + length, valid );
768 else if ( format == 2 )
769 gxv_kern_subtable_fmt2_validate( table, table + length, valid );
770 else if ( format == 3 )
771 gxv_kern_subtable_fmt3_validate( table, table + length, valid );
772 else
773 FT_INVALID_DATA;
774
775 Exit:
776 valid->subtable_length = length;
777 GXV_EXIT;
778 }
779
780
781 /*************************************************************************/
782 /*************************************************************************/
783 /***** *****/
784 /***** kern TABLE *****/
785 /***** *****/
786 /*************************************************************************/
787 /*************************************************************************/
788
789 static void
790 gxv_kern_validate_generic( FT_Bytes table,
791 FT_Face face,
792 FT_Bool classic_only,
793 GXV_kern_Dialect dialect_request,
794 FT_Validator ftvalid )
795 {
796 GXV_ValidatorRec validrec;
797 GXV_Validator valid = &validrec;
798
799 GXV_kern_DataRec kernrec;
800 GXV_kern_Data kern = &kernrec;
801
802 FT_Bytes p = table;
803 FT_Bytes limit = 0;
804
805 FT_ULong nTables = 0;
806 FT_UInt i;
807
808
809 valid->root = ftvalid;
810 valid->table_data = kern;
811 valid->face = face;
812
813 FT_TRACE3(( "validating `kern' table\n" ));
814 GXV_INIT;
815 KERN_DIALECT( valid ) = dialect_request;
816
817 GXV_LIMIT_CHECK( 2 );
818 GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p );
819 GXV_TRACE(( "version 0x%04x (higher 16bit)\n",
820 GXV_KERN_DATA( version ) ));
821
822 if ( 0x0001 < GXV_KERN_DATA( version ) )
823 FT_INVALID_FORMAT;
824 else if ( KERN_IS_CLASSIC( valid ) )
825 {
826 GXV_LIMIT_CHECK( 2 );
827 nTables = FT_NEXT_USHORT( p );
828 }
829 else if ( KERN_IS_NEW( valid ) )
830 {
831 if ( classic_only )
832 FT_INVALID_FORMAT;
833
834 if ( 0x0000 != FT_NEXT_USHORT( p ) )
835 FT_INVALID_FORMAT;
836
837 GXV_LIMIT_CHECK( 4 );
838 nTables = FT_NEXT_ULONG( p );
839 }
840
841 for ( i = 0; i < nTables; i++ )
842 {
843 GXV_TRACE(( "validating subtable %d/%d\n", i, nTables ));
844 /* p should be 32bit-aligned? */
845 gxv_kern_subtable_validate( p, 0, valid );
846 p += valid->subtable_length;
847 }
848
849 FT_TRACE4(( "\n" ));
850 }
851
852
853 FT_LOCAL_DEF( void )
854 gxv_kern_validate( FT_Bytes table,
855 FT_Face face,
856 FT_Validator ftvalid )
857 {
858 gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid );
859 }
860
861
862 FT_LOCAL_DEF( void )
863 gxv_kern_validate_classic( FT_Bytes table,
864 FT_Face face,
865 FT_Int dialect_flags,
866 FT_Validator ftvalid )
867 {
868 GXV_kern_Dialect dialect_request;
869
870
871 dialect_request = (GXV_kern_Dialect)dialect_flags;
872 gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid );
873 }
874
875
876 /* END */