Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/***************************************************************************/
2
/*                                                                         */
3
/*  gxvkern.c                                                              */
4
/*                                                                         */
5
/*    TrueTypeGX/AAT kern table validation (body).                         */
6
/*                                                                         */
7
/*  Copyright 2004-2007, 2013                                              */
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
#ifdef GXV_LOAD_UNUSED_VARS
131
      FT_Short   kernValue;
132
#endif
133
 
134
 
135
      /* left */
136
      gid_left  = FT_NEXT_USHORT( p );
137
      gxv_glyphid_validate( gid_left, valid );
138
 
139
      /* right */
140
      gid_right = FT_NEXT_USHORT( p );
141
      gxv_glyphid_validate( gid_right, valid );
142
 
143
      /* Pairs of left and right GIDs must be unique and sorted. */
144
      GXV_TRACE(( "left gid = %u, right gid = %u\n", gid_left, gid_right ));
145
      if ( gid_left == last_gid_left )
146
      {
147
        if ( last_gid_right < gid_right )
148
          last_gid_right = gid_right;
149
        else
150
          FT_INVALID_DATA;
151
      }
152
      else if ( last_gid_left < gid_left )
153
      {
154
        last_gid_left  = gid_left;
155
        last_gid_right = gid_right;
156
      }
157
      else
158
        FT_INVALID_DATA;
159
 
160
      /* skip the kern value */
161
#ifdef GXV_LOAD_UNUSED_VARS
162
      kernValue = FT_NEXT_SHORT( p );
163
#else
164
      p += 2;
165
#endif
166
    }
167
 
168
    GXV_EXIT;
169
  }
170
 
171
  static void
172
  gxv_kern_subtable_fmt0_validate( FT_Bytes       table,
173
                                   FT_Bytes       limit,
174
                                   GXV_Validator  valid )
175
  {
176
    FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
177
 
178
    FT_UShort  nPairs;
179
    FT_UShort  unitSize;
180
 
181
 
182
    GXV_NAME_ENTER( "kern subtable format 0" );
183
 
184
    unitSize = 2 + 2 + 2;
185
    nPairs   = 0;
186
 
187
    /* nPairs, searchRange, entrySelector, rangeShift */
188
    GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
189
    gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, valid );
190
    p += 2 + 2 + 2 + 2;
191
 
192
    gxv_kern_subtable_fmt0_pairs_validate( p, limit, nPairs, valid );
193
 
194
    GXV_EXIT;
195
  }
196
 
197
 
198
  /* ============================= format 1 ============================== */
199
 
200
 
201
  typedef struct  GXV_kern_fmt1_StateOptRec_
202
  {
203
    FT_UShort  valueTable;
204
    FT_UShort  valueTable_length;
205
 
206
  } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData;
207
 
208
 
209
  static void
210
  gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes       table,
211
                                          FT_Bytes       limit,
212
                                          GXV_Validator  valid )
213
  {
214
    FT_Bytes                       p = table;
215
    GXV_kern_fmt1_StateOptRecData  optdata =
216
      (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
217
 
218
 
219
    GXV_LIMIT_CHECK( 2 );
220
    optdata->valueTable = FT_NEXT_USHORT( p );
221
  }
222
 
223
 
224
  /*
225
   * passed tables_size covers whole StateTable, including kern fmt1 header
226
   */
227
  static void
228
  gxv_kern_subtable_fmt1_subtable_setup( FT_UShort      table_size,
229
                                         FT_UShort      classTable,
230
                                         FT_UShort      stateArray,
231
                                         FT_UShort      entryTable,
232
                                         FT_UShort*     classTable_length_p,
233
                                         FT_UShort*     stateArray_length_p,
234
                                         FT_UShort*     entryTable_length_p,
235
                                         GXV_Validator  valid )
236
  {
237
    FT_UShort  o[4];
238
    FT_UShort  *l[4];
239
    FT_UShort  buff[5];
240
 
241
    GXV_kern_fmt1_StateOptRecData  optdata =
242
      (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
243
 
244
 
245
    o[0] = classTable;
246
    o[1] = stateArray;
247
    o[2] = entryTable;
248
    o[3] = optdata->valueTable;
249
    l[0] = classTable_length_p;
250
    l[1] = stateArray_length_p;
251
    l[2] = entryTable_length_p;
252
    l[3] = &(optdata->valueTable_length);
253
 
254
    gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid );
255
  }
256
 
257
 
258
  /*
259
   * passed table & limit are of whole StateTable, not including subtables
260
   */
261
  static void
262
  gxv_kern_subtable_fmt1_entry_validate(
263
    FT_Byte                         state,
264
    FT_UShort                       flags,
265
    GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
266
    FT_Bytes                        table,
267
    FT_Bytes                        limit,
268
    GXV_Validator                   valid )
269
  {
270
#ifdef GXV_LOAD_UNUSED_VARS
271
    FT_UShort  push;
272
    FT_UShort  dontAdvance;
273
#endif
274
    FT_UShort  valueOffset;
275
#ifdef GXV_LOAD_UNUSED_VARS
276
    FT_UShort  kernAction;
277
    FT_UShort  kernValue;
278
#endif
279
 
280
    FT_UNUSED( state );
281
    FT_UNUSED( glyphOffset_p );
282
 
283
 
284
#ifdef GXV_LOAD_UNUSED_VARS
285
    push        = (FT_UShort)( ( flags >> 15 ) & 1      );
286
    dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1      );
287
#endif
288
    valueOffset = (FT_UShort)(   flags         & 0x3FFF );
289
 
290
    {
291
      GXV_kern_fmt1_StateOptRecData  vt_rec =
292
        (GXV_kern_fmt1_StateOptRecData)valid->statetable.optdata;
293
      FT_Bytes  p;
294
 
295
 
296
      if ( valueOffset < vt_rec->valueTable )
297
        FT_INVALID_OFFSET;
298
 
299
      p     = table + valueOffset;
300
      limit = table + vt_rec->valueTable + vt_rec->valueTable_length;
301
 
302
      GXV_LIMIT_CHECK( 2 + 2 );
303
#ifdef GXV_LOAD_UNUSED_VARS
304
      kernAction = FT_NEXT_USHORT( p );
305
      kernValue  = FT_NEXT_USHORT( p );
306
#endif
307
    }
308
  }
309
 
310
 
311
  static void
312
  gxv_kern_subtable_fmt1_validate( FT_Bytes       table,
313
                                   FT_Bytes       limit,
314
                                   GXV_Validator  valid )
315
  {
316
    FT_Bytes                   p = table;
317
    GXV_kern_fmt1_StateOptRec  vt_rec;
318
 
319
 
320
    GXV_NAME_ENTER( "kern subtable format 1" );
321
 
322
    valid->statetable.optdata =
323
      &vt_rec;
324
    valid->statetable.optdata_load_func =
325
      gxv_kern_subtable_fmt1_valueTable_load;
326
    valid->statetable.subtable_setup_func =
327
      gxv_kern_subtable_fmt1_subtable_setup;
328
    valid->statetable.entry_glyphoffset_fmt =
329
      GXV_GLYPHOFFSET_NONE;
330
    valid->statetable.entry_validate_func =
331
      gxv_kern_subtable_fmt1_entry_validate;
332
 
333
    gxv_StateTable_validate( p, limit, valid );
334
 
335
    GXV_EXIT;
336
  }
337
 
338
 
339
  /* ================ Data for Class-Based Subtables 2, 3 ================ */
340
 
341
  typedef enum  GXV_kern_ClassSpec_
342
  {
343
    GXV_KERN_CLS_L = 0,
344
    GXV_KERN_CLS_R
345
 
346
  } GXV_kern_ClassSpec;
347
 
348
 
349
  /* ============================= format 2 ============================== */
350
 
351
  /* ---------------------- format 2 specific data ----------------------- */
352
 
353
  typedef struct  GXV_kern_subtable_fmt2_DataRec_
354
  {
355
    FT_UShort         rowWidth;
356
    FT_UShort         array;
357
    FT_UShort         offset_min[2];
358
    FT_UShort         offset_max[2];
359
    const FT_String*  class_tag[2];
360
    GXV_odtect_Range  odtect;
361
 
362
  } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data;
363
 
364
 
365
#define GXV_KERN_FMT2_DATA( field )                         \
366
        ( ( (GXV_kern_subtable_fmt2_DataRec *)              \
367
              ( GXV_KERN_DATA( subtable_data ) ) )->field )
368
 
369
 
370
  /* -------------------------- utility functions ----------------------- */
371
 
372
  static void
373
  gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes            table,
374
                                          FT_Bytes            limit,
375
                                          GXV_kern_ClassSpec  spec,
376
                                          GXV_Validator       valid )
377
  {
378
    const FT_String*  tag    = GXV_KERN_FMT2_DATA( class_tag[spec] );
379
    GXV_odtect_Range  odtect = GXV_KERN_FMT2_DATA( odtect );
380
 
381
    FT_Bytes   p = table;
382
    FT_UShort  firstGlyph;
383
    FT_UShort  nGlyphs;
384
 
385
 
386
    GXV_NAME_ENTER( "kern format 2 classTable" );
387
 
388
    GXV_LIMIT_CHECK( 2 + 2 );
389
    firstGlyph = FT_NEXT_USHORT( p );
390
    nGlyphs    = FT_NEXT_USHORT( p );
391
    GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n",
392
                tag, firstGlyph, nGlyphs ));
393
 
394
    gxv_glyphid_validate( firstGlyph, valid );
395
    gxv_glyphid_validate( (FT_UShort)( firstGlyph + nGlyphs - 1 ), valid );
396
 
397
    gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ),
398
                                &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ),
399
                                &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ),
400
                                valid );
401
 
402
    gxv_odtect_add_range( table, 2 * nGlyphs, tag, odtect );
403
 
404
    GXV_EXIT;
405
  }
406
 
407
 
408
  static void
409
  gxv_kern_subtable_fmt2_validate( FT_Bytes       table,
410
                                   FT_Bytes       limit,
411
                                   GXV_Validator  valid )
412
  {
413
    GXV_ODTECT( 3, odtect );
414
    GXV_kern_subtable_fmt2_DataRec  fmt2_rec =
415
      { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL };
416
 
417
    FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
418
    FT_UShort  leftOffsetTable;
419
    FT_UShort  rightOffsetTable;
420
 
421
 
422
    GXV_NAME_ENTER( "kern subtable format 2" );
423
 
424
    GXV_ODTECT_INIT( odtect );
425
    fmt2_rec.odtect = odtect;
426
    GXV_KERN_DATA( subtable_data ) = &fmt2_rec;
427
 
428
    GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
429
    GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p );
430
    leftOffsetTable                = FT_NEXT_USHORT( p );
431
    rightOffsetTable               = FT_NEXT_USHORT( p );
432
    GXV_KERN_FMT2_DATA( array )    = FT_NEXT_USHORT( p );
433
 
434
    GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) ));
435
 
436
 
437
    GXV_LIMIT_CHECK( leftOffsetTable );
438
    GXV_LIMIT_CHECK( rightOffsetTable );
439
    GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) );
440
 
441
    gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit,
442
                                            GXV_KERN_CLS_L, valid );
443
 
444
    gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit,
445
                                            GXV_KERN_CLS_R, valid );
446
 
447
    if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] ) +
448
           GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] )
449
         < GXV_KERN_FMT2_DATA( array )                      )
450
      FT_INVALID_OFFSET;
451
 
452
    gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ),
453
                          GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] )
454
                            + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] )
455
                            - GXV_KERN_FMT2_DATA( array ),
456
                          "array", odtect );
457
 
458
    gxv_odtect_validate( odtect, valid );
459
 
460
    GXV_EXIT;
461
  }
462
 
463
 
464
  /* ============================= format 3 ============================== */
465
 
466
  static void
467
  gxv_kern_subtable_fmt3_validate( FT_Bytes       table,
468
                                   FT_Bytes       limit,
469
                                   GXV_Validator  valid )
470
  {
471
    FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
472
    FT_UShort  glyphCount;
473
    FT_Byte    kernValueCount;
474
    FT_Byte    leftClassCount;
475
    FT_Byte    rightClassCount;
476
    FT_Byte    flags;
477
 
478
 
479
    GXV_NAME_ENTER( "kern subtable format 3" );
480
 
481
    GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 );
482
    glyphCount      = FT_NEXT_USHORT( p );
483
    kernValueCount  = FT_NEXT_BYTE( p );
484
    leftClassCount  = FT_NEXT_BYTE( p );
485
    rightClassCount = FT_NEXT_BYTE( p );
486
    flags           = FT_NEXT_BYTE( p );
487
 
488
    if ( valid->face->num_glyphs != glyphCount )
489
    {
490
      GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n",
491
                  valid->face->num_glyphs, glyphCount ));
492
      GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
493
    }
494
 
495
    if ( flags != 0 )
496
      GXV_TRACE(( "kern subtable fmt3 has nonzero value"
497
                  " (%d) in unused flag\n", flags ));
498
    /*
499
     * just skip kernValue[kernValueCount]
500
     */
501
    GXV_LIMIT_CHECK( 2 * kernValueCount );
502
    p += 2 * kernValueCount;
503
 
504
    /*
505
     * check leftClass[gid] < leftClassCount
506
     */
507
    {
508
      FT_Byte  min, max;
509
 
510
 
511
      GXV_LIMIT_CHECK( glyphCount );
512
      gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
513
      p += valid->subtable_length;
514
 
515
      if ( leftClassCount < max )
516
        FT_INVALID_DATA;
517
    }
518
 
519
    /*
520
     * check rightClass[gid] < rightClassCount
521
     */
522
    {
523
      FT_Byte  min, max;
524
 
525
 
526
      GXV_LIMIT_CHECK( glyphCount );
527
      gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
528
      p += valid->subtable_length;
529
 
530
      if ( rightClassCount < max )
531
        FT_INVALID_DATA;
532
    }
533
 
534
    /*
535
     * check kernIndex[i, j] < kernValueCount
536
     */
537
    {
538
      FT_UShort  i, j;
539
 
540
 
541
      for ( i = 0; i < leftClassCount; i++ )
542
      {
543
        for ( j = 0; j < rightClassCount; j++ )
544
        {
545
          GXV_LIMIT_CHECK( 1 );
546
          if ( kernValueCount < FT_NEXT_BYTE( p ) )
547
            FT_INVALID_OFFSET;
548
        }
549
      }
550
    }
551
 
552
    valid->subtable_length = p - table;
553
 
554
    GXV_EXIT;
555
  }
556
 
557
 
558
  static FT_Bool
559
  gxv_kern_coverage_new_apple_validate( FT_UShort      coverage,
560
                                        FT_UShort*     format,
561
                                        GXV_Validator  valid )
562
  {
563
    /* new Apple-dialect */
564
#ifdef GXV_LOAD_TRACE_VARS
565
    FT_Bool  kernVertical;
566
    FT_Bool  kernCrossStream;
567
    FT_Bool  kernVariation;
568
#endif
569
 
570
    FT_UNUSED( valid );
571
 
572
 
573
    /* reserved bits = 0 */
574
    if ( coverage & 0x1FFC )
575
      return FALSE;
576
 
577
#ifdef GXV_LOAD_TRACE_VARS
578
    kernVertical    = FT_BOOL( ( coverage >> 15 ) & 1 );
579
    kernCrossStream = FT_BOOL( ( coverage >> 14 ) & 1 );
580
    kernVariation   = FT_BOOL( ( coverage >> 13 ) & 1 );
581
#endif
582
 
583
    *format = (FT_UShort)( coverage & 0x0003 );
584
 
585
    GXV_TRACE(( "new Apple-dialect: "
586
                "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n",
587
                 !kernVertical, kernCrossStream, kernVariation, *format ));
588
 
589
    GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
590
 
591
    return TRUE;
592
  }
593
 
594
 
595
  static FT_Bool
596
  gxv_kern_coverage_classic_apple_validate( FT_UShort      coverage,
597
                                            FT_UShort*     format,
598
                                            GXV_Validator  valid )
599
  {
600
    /* classic Apple-dialect */
601
#ifdef GXV_LOAD_TRACE_VARS
602
    FT_Bool  horizontal;
603
    FT_Bool  cross_stream;
604
#endif
605
 
606
 
607
    /* check expected flags, but don't check if MS-dialect is impossible */
608
    if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) )
609
      return FALSE;
610
 
611
    /* reserved bits = 0 */
612
    if ( coverage & 0x02FC )
613
      return FALSE;
614
 
615
#ifdef GXV_LOAD_TRACE_VARS
616
    horizontal   = FT_BOOL( ( coverage >> 15 ) & 1 );
617
    cross_stream = FT_BOOL( ( coverage >> 13 ) & 1 );
618
#endif
619
 
620
    *format = (FT_UShort)( coverage & 0x0003 );
621
 
622
    GXV_TRACE(( "classic Apple-dialect: "
623
                "horizontal=%d, cross-stream=%d, format=%d\n",
624
                 horizontal, cross_stream, *format ));
625
 
626
    /* format 1 requires GX State Machine, too new for classic */
627
    if ( *format == 1 )
628
      return FALSE;
629
 
630
    GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
631
 
632
    return TRUE;
633
  }
634
 
635
 
636
  static FT_Bool
637
  gxv_kern_coverage_classic_microsoft_validate( FT_UShort      coverage,
638
                                                FT_UShort*     format,
639
                                                GXV_Validator  valid )
640
  {
641
    /* classic Microsoft-dialect */
642
#ifdef GXV_LOAD_TRACE_VARS
643
    FT_Bool  horizontal;
644
    FT_Bool  minimum;
645
    FT_Bool  cross_stream;
646
    FT_Bool  override;
647
#endif
648
 
649
    FT_UNUSED( valid );
650
 
651
 
652
    /* reserved bits = 0 */
653
    if ( coverage & 0xFDF0 )
654
      return FALSE;
655
 
656
#ifdef GXV_LOAD_TRACE_VARS
657
    horizontal   = FT_BOOL(   coverage        & 1 );
658
    minimum      = FT_BOOL( ( coverage >> 1 ) & 1 );
659
    cross_stream = FT_BOOL( ( coverage >> 2 ) & 1 );
660
    override     = FT_BOOL( ( coverage >> 3 ) & 1 );
661
#endif
662
 
663
    *format = (FT_UShort)( ( coverage >> 8 ) & 0x0003 );
664
 
665
    GXV_TRACE(( "classic Microsoft-dialect: "
666
                "horizontal=%d, minimum=%d, cross-stream=%d, "
667
                "override=%d, format=%d\n",
668
                horizontal, minimum, cross_stream, override, *format ));
669
 
670
    if ( *format == 2 )
671
      GXV_TRACE((
672
        "kerning values in Microsoft format 2 subtable are ignored\n" ));
673
 
674
    return TRUE;
675
  }
676
 
677
 
678
  /*************************************************************************/
679
  /*************************************************************************/
680
  /*****                                                               *****/
681
  /*****                            MAIN                               *****/
682
  /*****                                                               *****/
683
  /*************************************************************************/
684
  /*************************************************************************/
685
 
686
  static GXV_kern_Dialect
687
  gxv_kern_coverage_validate( FT_UShort      coverage,
688
                              FT_UShort*     format,
689
                              GXV_Validator  valid )
690
  {
691
    GXV_kern_Dialect  result = KERN_DIALECT_UNKNOWN;
692
 
693
 
694
    GXV_NAME_ENTER( "validating coverage" );
695
 
696
    GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage ));
697
 
698
    if ( KERN_IS_NEW( valid ) )
699
    {
700
      if ( gxv_kern_coverage_new_apple_validate( coverage,
701
                                                 format,
702
                                                 valid ) )
703
      {
704
        result = KERN_DIALECT_APPLE;
705
        goto Exit;
706
      }
707
    }
708
 
709
    if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) )
710
    {
711
      if ( gxv_kern_coverage_classic_apple_validate( coverage,
712
                                                     format,
713
                                                     valid ) )
714
      {
715
        result = KERN_DIALECT_APPLE;
716
        goto Exit;
717
      }
718
    }
719
 
720
    if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) )
721
    {
722
      if ( gxv_kern_coverage_classic_microsoft_validate( coverage,
723
                                                         format,
724
                                                         valid ) )
725
      {
726
        result = KERN_DIALECT_MS;
727
        goto Exit;
728
      }
729
    }
730
 
731
    GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" ));
732
 
733
  Exit:
734
    GXV_EXIT;
735
    return result;
736
  }
737
 
738
 
739
  static void
740
  gxv_kern_subtable_validate( FT_Bytes       table,
741
                              FT_Bytes       limit,
742
                              GXV_Validator  valid )
743
  {
744
    FT_Bytes   p = table;
745
#ifdef GXV_LOAD_TRACE_VARS
746
    FT_UShort  version = 0;    /* MS only: subtable version, unused */
747
#endif
748
    FT_ULong   length;         /* MS: 16bit, Apple: 32bit*/
749
    FT_UShort  coverage;
750
#ifdef GXV_LOAD_TRACE_VARS
751
    FT_UShort  tupleIndex = 0; /* Apple only */
752
#endif
753
    FT_UShort  u16[2];
754
    FT_UShort  format = 255;   /* subtable format */
755
 
756
 
757
    GXV_NAME_ENTER( "kern subtable" );
758
 
759
    GXV_LIMIT_CHECK( 2 + 2 + 2 );
760
    u16[0]   = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */
761
    u16[1]   = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */
762
    coverage = FT_NEXT_USHORT( p );
763
 
764
    switch ( gxv_kern_coverage_validate( coverage, &format, valid ) )
765
    {
766
    case KERN_DIALECT_MS:
767
#ifdef GXV_LOAD_TRACE_VARS
768
      version    = u16[0];
769
#endif
770
      length     = u16[1];
771
#ifdef GXV_LOAD_TRACE_VARS
772
      tupleIndex = 0;
773
#endif
774
      GXV_TRACE(( "Subtable version = %d\n", version ));
775
      GXV_TRACE(( "Subtable length = %d\n", length ));
776
      break;
777
 
778
    case KERN_DIALECT_APPLE:
779
#ifdef GXV_LOAD_TRACE_VARS
780
      version    = 0;
781
#endif
782
      length     = ( u16[0] << 16 ) + u16[1];
783
#ifdef GXV_LOAD_TRACE_VARS
784
      tupleIndex = 0;
785
#endif
786
      GXV_TRACE(( "Subtable length = %d\n", length ));
787
 
788
      if ( KERN_IS_NEW( valid ) )
789
      {
790
        GXV_LIMIT_CHECK( 2 );
791
#ifdef GXV_LOAD_TRACE_VARS
792
        tupleIndex = FT_NEXT_USHORT( p );
793
#else
794
        p += 2;
795
#endif
796
        GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex ));
797
      }
798
      break;
799
 
800
    default:
801
      length = u16[1];
802
      GXV_TRACE(( "cannot detect subtable dialect, "
803
                  "just skip %d byte\n", length ));
804
      goto Exit;
805
    }
806
 
807
    /* formats 1, 2, 3 require the position of the start of this subtable */
808
    if ( format == 0 )
809
      gxv_kern_subtable_fmt0_validate( table, table + length, valid );
810
    else if ( format == 1 )
811
      gxv_kern_subtable_fmt1_validate( table, table + length, valid );
812
    else if ( format == 2 )
813
      gxv_kern_subtable_fmt2_validate( table, table + length, valid );
814
    else if ( format == 3 )
815
      gxv_kern_subtable_fmt3_validate( table, table + length, valid );
816
    else
817
      FT_INVALID_DATA;
818
 
819
  Exit:
820
    valid->subtable_length = length;
821
    GXV_EXIT;
822
  }
823
 
824
 
825
  /*************************************************************************/
826
  /*************************************************************************/
827
  /*****                                                               *****/
828
  /*****                         kern TABLE                            *****/
829
  /*****                                                               *****/
830
  /*************************************************************************/
831
  /*************************************************************************/
832
 
833
  static void
834
  gxv_kern_validate_generic( FT_Bytes          table,
835
                             FT_Face           face,
836
                             FT_Bool           classic_only,
837
                             GXV_kern_Dialect  dialect_request,
838
                             FT_Validator      ftvalid )
839
  {
840
    GXV_ValidatorRec   validrec;
841
    GXV_Validator      valid = &validrec;
842
 
843
    GXV_kern_DataRec   kernrec;
844
    GXV_kern_Data      kern = &kernrec;
845
 
846
    FT_Bytes           p     = table;
847
    FT_Bytes           limit = 0;
848
 
849
    FT_ULong           nTables = 0;
850
    FT_UInt            i;
851
 
852
 
853
    valid->root       = ftvalid;
854
    valid->table_data = kern;
855
    valid->face       = face;
856
 
857
    FT_TRACE3(( "validating `kern' table\n" ));
858
    GXV_INIT;
859
    KERN_DIALECT( valid ) = dialect_request;
860
 
861
    GXV_LIMIT_CHECK( 2 );
862
    GXV_KERN_DATA( version ) = (GXV_kern_Version)FT_NEXT_USHORT( p );
863
    GXV_TRACE(( "version 0x%04x (higher 16bit)\n",
864
                GXV_KERN_DATA( version ) ));
865
 
866
    if ( 0x0001 < GXV_KERN_DATA( version ) )
867
      FT_INVALID_FORMAT;
868
    else if ( KERN_IS_CLASSIC( valid ) )
869
    {
870
      GXV_LIMIT_CHECK( 2 );
871
      nTables = FT_NEXT_USHORT( p );
872
    }
873
    else if ( KERN_IS_NEW( valid ) )
874
    {
875
      if ( classic_only )
876
        FT_INVALID_FORMAT;
877
 
878
      if ( 0x0000 != FT_NEXT_USHORT( p ) )
879
        FT_INVALID_FORMAT;
880
 
881
      GXV_LIMIT_CHECK( 4 );
882
      nTables = FT_NEXT_ULONG( p );
883
    }
884
 
885
    for ( i = 0; i < nTables; i++ )
886
    {
887
      GXV_TRACE(( "validating subtable %d/%d\n", i, nTables ));
888
      /* p should be 32bit-aligned? */
889
      gxv_kern_subtable_validate( p, 0, valid );
890
      p += valid->subtable_length;
891
    }
892
 
893
    FT_TRACE4(( "\n" ));
894
  }
895
 
896
 
897
  FT_LOCAL_DEF( void )
898
  gxv_kern_validate( FT_Bytes      table,
899
                     FT_Face       face,
900
                     FT_Validator  ftvalid )
901
  {
902
    gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid );
903
  }
904
 
905
 
906
  FT_LOCAL_DEF( void )
907
  gxv_kern_validate_classic( FT_Bytes      table,
908
                             FT_Face       face,
909
                             FT_Int        dialect_flags,
910
                             FT_Validator  ftvalid )
911
  {
912
    GXV_kern_Dialect  dialect_request;
913
 
914
 
915
    dialect_request = (GXV_kern_Dialect)dialect_flags;
916
    gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid );
917
  }
918
 
919
 
920
/* END */