PageRenderTime 131ms CodeModel.GetById 27ms app.highlight 91ms RepoModel.GetById 2ms app.codeStats 0ms

/src/freetype/src/sfnt/ttcmap.c

https://bitbucket.org/cabalistic/ogredeps/
C | 3512 lines | 2201 code | 753 blank | 558 comment | 421 complexity | e2ba5752d3f982bbb5241ef0bfd41888 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/***************************************************************************/
   2/*                                                                         */
   3/*  ttcmap.c                                                               */
   4/*                                                                         */
   5/*    TrueType character mapping table (cmap) support (body).              */
   6/*                                                                         */
   7/*  Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 <ft2build.h>
  20#include FT_INTERNAL_DEBUG_H
  21
  22#include "sferrors.h"           /* must come before FT_INTERNAL_VALIDATE_H */
  23
  24#include FT_INTERNAL_VALIDATE_H
  25#include FT_INTERNAL_STREAM_H
  26#include "ttload.h"
  27#include "ttcmap.h"
  28#include "sfntpic.h"
  29
  30
  31  /*************************************************************************/
  32  /*                                                                       */
  33  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  34  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  35  /* messages during execution.                                            */
  36  /*                                                                       */
  37#undef  FT_COMPONENT
  38#define FT_COMPONENT  trace_ttcmap
  39
  40
  41#define TT_PEEK_SHORT   FT_PEEK_SHORT
  42#define TT_PEEK_USHORT  FT_PEEK_USHORT
  43#define TT_PEEK_UINT24  FT_PEEK_UOFF3
  44#define TT_PEEK_LONG    FT_PEEK_LONG
  45#define TT_PEEK_ULONG   FT_PEEK_ULONG
  46
  47#define TT_NEXT_SHORT   FT_NEXT_SHORT
  48#define TT_NEXT_USHORT  FT_NEXT_USHORT
  49#define TT_NEXT_UINT24  FT_NEXT_UOFF3
  50#define TT_NEXT_LONG    FT_NEXT_LONG
  51#define TT_NEXT_ULONG   FT_NEXT_ULONG
  52
  53
  54  FT_CALLBACK_DEF( FT_Error )
  55  tt_cmap_init( TT_CMap   cmap,
  56                FT_Byte*  table )
  57  {
  58    cmap->data = table;
  59    return SFNT_Err_Ok;
  60  }
  61
  62
  63  /*************************************************************************/
  64  /*************************************************************************/
  65  /*****                                                               *****/
  66  /*****                           FORMAT 0                            *****/
  67  /*****                                                               *****/
  68  /*************************************************************************/
  69  /*************************************************************************/
  70
  71  /*************************************************************************/
  72  /*                                                                       */
  73  /* TABLE OVERVIEW                                                        */
  74  /* --------------                                                        */
  75  /*                                                                       */
  76  /*   NAME        OFFSET         TYPE          DESCRIPTION                */
  77  /*                                                                       */
  78  /*   format      0              USHORT        must be 0                  */
  79  /*   length      2              USHORT        table length in bytes      */
  80  /*   language    4              USHORT        Mac language code          */
  81  /*   glyph_ids   6              BYTE[256]     array of glyph indices     */
  82  /*               262                                                     */
  83  /*                                                                       */
  84
  85#ifdef TT_CONFIG_CMAP_FORMAT_0
  86
  87  FT_CALLBACK_DEF( FT_Error )
  88  tt_cmap0_validate( FT_Byte*      table,
  89                     FT_Validator  valid )
  90  {
  91    FT_Byte*  p      = table + 2;
  92    FT_UInt   length = TT_NEXT_USHORT( p );
  93
  94
  95    if ( table + length > valid->limit || length < 262 )
  96      FT_INVALID_TOO_SHORT;
  97
  98    /* check glyph indices whenever necessary */
  99    if ( valid->level >= FT_VALIDATE_TIGHT )
 100    {
 101      FT_UInt  n, idx;
 102
 103
 104      p = table + 6;
 105      for ( n = 0; n < 256; n++ )
 106      {
 107        idx = *p++;
 108        if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
 109          FT_INVALID_GLYPH_ID;
 110      }
 111    }
 112
 113    return SFNT_Err_Ok;
 114  }
 115
 116
 117  FT_CALLBACK_DEF( FT_UInt )
 118  tt_cmap0_char_index( TT_CMap    cmap,
 119                       FT_UInt32  char_code )
 120  {
 121    FT_Byte*  table = cmap->data;
 122
 123
 124    return char_code < 256 ? table[6 + char_code] : 0;
 125  }
 126
 127
 128  FT_CALLBACK_DEF( FT_UInt32 )
 129  tt_cmap0_char_next( TT_CMap     cmap,
 130                      FT_UInt32  *pchar_code )
 131  {
 132    FT_Byte*   table    = cmap->data;
 133    FT_UInt32  charcode = *pchar_code;
 134    FT_UInt32  result   = 0;
 135    FT_UInt    gindex   = 0;
 136
 137
 138    table += 6;  /* go to glyph IDs */
 139    while ( ++charcode < 256 )
 140    {
 141      gindex = table[charcode];
 142      if ( gindex != 0 )
 143      {
 144        result = charcode;
 145        break;
 146      }
 147    }
 148
 149    *pchar_code = result;
 150    return gindex;
 151  }
 152
 153
 154  FT_CALLBACK_DEF( FT_Error )
 155  tt_cmap0_get_info( TT_CMap       cmap,
 156                     TT_CMapInfo  *cmap_info )
 157  {
 158    FT_Byte*  p = cmap->data + 4;
 159
 160
 161    cmap_info->format   = 0;
 162    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
 163
 164    return SFNT_Err_Ok;
 165  }
 166
 167
 168  FT_DEFINE_TT_CMAP(tt_cmap0_class_rec,
 169      sizeof ( TT_CMapRec ),
 170
 171      (FT_CMap_InitFunc)     tt_cmap_init,
 172      (FT_CMap_DoneFunc)     NULL,
 173      (FT_CMap_CharIndexFunc)tt_cmap0_char_index,
 174      (FT_CMap_CharNextFunc) tt_cmap0_char_next,
 175
 176      NULL, NULL, NULL, NULL, NULL
 177    ,
 178    0,
 179    (TT_CMap_ValidateFunc)   tt_cmap0_validate,
 180    (TT_CMap_Info_GetFunc)   tt_cmap0_get_info
 181  )
 182
 183#endif /* TT_CONFIG_CMAP_FORMAT_0 */
 184
 185
 186  /*************************************************************************/
 187  /*************************************************************************/
 188  /*****                                                               *****/
 189  /*****                          FORMAT 2                             *****/
 190  /*****                                                               *****/
 191  /***** This is used for certain CJK encodings that encode text in a  *****/
 192  /***** mixed 8/16 bits encoding along the following lines:           *****/
 193  /*****                                                               *****/
 194  /***** * Certain byte values correspond to an 8-bit character code   *****/
 195  /*****   (typically in the range 0..127 for ASCII compatibility).    *****/
 196  /*****                                                               *****/
 197  /***** * Certain byte values signal the first byte of a 2-byte       *****/
 198  /*****   character code (but these values are also valid as the      *****/
 199  /*****   second byte of a 2-byte character).                         *****/
 200  /*****                                                               *****/
 201  /***** The following charmap lookup and iteration functions all      *****/
 202  /***** assume that the value "charcode" correspond to following:     *****/
 203  /*****                                                               *****/
 204  /*****   - For one byte characters, "charcode" is simply the         *****/
 205  /*****     character code.                                           *****/
 206  /*****                                                               *****/
 207  /*****   - For two byte characters, "charcode" is the 2-byte         *****/
 208  /*****     character code in big endian format.  More exactly:       *****/
 209  /*****                                                               *****/
 210  /*****       (charcode >> 8)    is the first byte value              *****/
 211  /*****       (charcode & 0xFF)  is the second byte value             *****/
 212  /*****                                                               *****/
 213  /***** Note that not all values of "charcode" are valid according    *****/
 214  /***** to these rules, and the function moderately check the         *****/
 215  /***** arguments.                                                    *****/
 216  /*****                                                               *****/
 217  /*************************************************************************/
 218  /*************************************************************************/
 219
 220  /*************************************************************************/
 221  /*                                                                       */
 222  /* TABLE OVERVIEW                                                        */
 223  /* --------------                                                        */
 224  /*                                                                       */
 225  /*   NAME        OFFSET         TYPE            DESCRIPTION              */
 226  /*                                                                       */
 227  /*   format      0              USHORT          must be 2                */
 228  /*   length      2              USHORT          table length in bytes    */
 229  /*   language    4              USHORT          Mac language code        */
 230  /*   keys        6              USHORT[256]     sub-header keys          */
 231  /*   subs        518            SUBHEAD[NSUBS]  sub-headers array        */
 232  /*   glyph_ids   518+NSUB*8     USHORT[]        glyph ID array           */
 233  /*                                                                       */
 234  /* The `keys' table is used to map charcode high-bytes to sub-headers.   */
 235  /* The value of `NSUBS' is the number of sub-headers defined in the      */
 236  /* table and is computed by finding the maximum of the `keys' table.     */
 237  /*                                                                       */
 238  /* Note that for any n, `keys[n]' is a byte offset within the `subs'     */
 239  /* table, i.e., it is the corresponding sub-header index multiplied      */
 240  /* by 8.                                                                 */
 241  /*                                                                       */
 242  /* Each sub-header has the following format:                             */
 243  /*                                                                       */
 244  /*   NAME        OFFSET      TYPE            DESCRIPTION                 */
 245  /*                                                                       */
 246  /*   first       0           USHORT          first valid low-byte        */
 247  /*   count       2           USHORT          number of valid low-bytes   */
 248  /*   delta       4           SHORT           see below                   */
 249  /*   offset      6           USHORT          see below                   */
 250  /*                                                                       */
 251  /* A sub-header defines, for each high-byte, the range of valid          */
 252  /* low-bytes within the charmap.  Note that the range defined by `first' */
 253  /* and `count' must be completely included in the interval [0..255]      */
 254  /* according to the specification.                                       */
 255  /*                                                                       */
 256  /* If a character code is contained within a given sub-header, then      */
 257  /* mapping it to a glyph index is done as follows:                       */
 258  /*                                                                       */
 259  /* * The value of `offset' is read.  This is a _byte_ distance from the  */
 260  /*   location of the `offset' field itself into a slice of the           */
 261  /*   `glyph_ids' table.  Let's call it `slice' (it is a USHORT[] too).   */
 262  /*                                                                       */
 263  /* * The value `slice[char.lo - first]' is read.  If it is 0, there is   */
 264  /*   no glyph for the charcode.  Otherwise, the value of `delta' is      */
 265  /*   added to it (modulo 65536) to form a new glyph index.               */
 266  /*                                                                       */
 267  /* It is up to the validation routine to check that all offsets fall     */
 268  /* within the glyph IDs table (and not within the `subs' table itself or */
 269  /* outside of the CMap).                                                 */
 270  /*                                                                       */
 271
 272#ifdef TT_CONFIG_CMAP_FORMAT_2
 273
 274  FT_CALLBACK_DEF( FT_Error )
 275  tt_cmap2_validate( FT_Byte*      table,
 276                     FT_Validator  valid )
 277  {
 278    FT_Byte*  p      = table + 2;           /* skip format */
 279    FT_UInt   length = TT_PEEK_USHORT( p );
 280    FT_UInt   n, max_subs;
 281    FT_Byte*  keys;                         /* keys table */
 282    FT_Byte*  subs;                         /* sub-headers */
 283    FT_Byte*  glyph_ids;                    /* glyph ID array */
 284
 285
 286    if ( table + length > valid->limit || length < 6 + 512 )
 287      FT_INVALID_TOO_SHORT;
 288
 289    keys = table + 6;
 290
 291    /* parse keys to compute sub-headers count */
 292    p        = keys;
 293    max_subs = 0;
 294    for ( n = 0; n < 256; n++ )
 295    {
 296      FT_UInt  idx = TT_NEXT_USHORT( p );
 297
 298
 299      /* value must be multiple of 8 */
 300      if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 )
 301        FT_INVALID_DATA;
 302
 303      idx >>= 3;
 304
 305      if ( idx > max_subs )
 306        max_subs = idx;
 307    }
 308
 309    FT_ASSERT( p == table + 518 );
 310
 311    subs      = p;
 312    glyph_ids = subs + (max_subs + 1) * 8;
 313    if ( glyph_ids > valid->limit )
 314      FT_INVALID_TOO_SHORT;
 315
 316    /* parse sub-headers */
 317    for ( n = 0; n <= max_subs; n++ )
 318    {
 319      FT_UInt   first_code, code_count, offset;
 320      FT_Int    delta;
 321      FT_Byte*  ids;
 322
 323
 324      first_code = TT_NEXT_USHORT( p );
 325      code_count = TT_NEXT_USHORT( p );
 326      delta      = TT_NEXT_SHORT( p );
 327      offset     = TT_NEXT_USHORT( p );
 328
 329      /* many Dynalab fonts have empty sub-headers */
 330      if ( code_count == 0 )
 331        continue;
 332
 333      /* check range within 0..255 */
 334      if ( valid->level >= FT_VALIDATE_PARANOID )
 335      {
 336        if ( first_code >= 256 || first_code + code_count > 256 )
 337          FT_INVALID_DATA;
 338      }
 339
 340      /* check offset */
 341      if ( offset != 0 )
 342      {
 343        ids = p - 2 + offset;
 344        if ( ids < glyph_ids || ids + code_count*2 > table + length )
 345          FT_INVALID_OFFSET;
 346
 347        /* check glyph IDs */
 348        if ( valid->level >= FT_VALIDATE_TIGHT )
 349        {
 350          FT_Byte*  limit = p + code_count * 2;
 351          FT_UInt   idx;
 352
 353
 354          for ( ; p < limit; )
 355          {
 356            idx = TT_NEXT_USHORT( p );
 357            if ( idx != 0 )
 358            {
 359              idx = ( idx + delta ) & 0xFFFFU;
 360              if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
 361                FT_INVALID_GLYPH_ID;
 362            }
 363          }
 364        }
 365      }
 366    }
 367
 368    return SFNT_Err_Ok;
 369  }
 370
 371
 372  /* return sub header corresponding to a given character code */
 373  /* NULL on invalid charcode                                  */
 374  static FT_Byte*
 375  tt_cmap2_get_subheader( FT_Byte*   table,
 376                          FT_UInt32  char_code )
 377  {
 378    FT_Byte*  result = NULL;
 379
 380
 381    if ( char_code < 0x10000UL )
 382    {
 383      FT_UInt   char_lo = (FT_UInt)( char_code & 0xFF );
 384      FT_UInt   char_hi = (FT_UInt)( char_code >> 8 );
 385      FT_Byte*  p       = table + 6;    /* keys table */
 386      FT_Byte*  subs    = table + 518;  /* subheaders table */
 387      FT_Byte*  sub;
 388
 389
 390      if ( char_hi == 0 )
 391      {
 392        /* an 8-bit character code -- we use subHeader 0 in this case */
 393        /* to test whether the character code is in the charmap       */
 394        /*                                                            */
 395        sub = subs;  /* jump to first sub-header */
 396
 397        /* check that the sub-header for this byte is 0, which */
 398        /* indicates that it is really a valid one-byte value  */
 399        /* Otherwise, return 0                                 */
 400        /*                                                     */
 401        p += char_lo * 2;
 402        if ( TT_PEEK_USHORT( p ) != 0 )
 403          goto Exit;
 404      }
 405      else
 406      {
 407        /* a 16-bit character code */
 408
 409        /* jump to key entry  */
 410        p  += char_hi * 2;
 411        /* jump to sub-header */
 412        sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) );
 413
 414        /* check that the high byte isn't a valid one-byte value */
 415        if ( sub == subs )
 416          goto Exit;
 417      }
 418      result = sub;
 419    }
 420  Exit:
 421    return result;
 422  }
 423
 424
 425  FT_CALLBACK_DEF( FT_UInt )
 426  tt_cmap2_char_index( TT_CMap    cmap,
 427                       FT_UInt32  char_code )
 428  {
 429    FT_Byte*  table   = cmap->data;
 430    FT_UInt   result  = 0;
 431    FT_Byte*  subheader;
 432
 433
 434    subheader = tt_cmap2_get_subheader( table, char_code );
 435    if ( subheader )
 436    {
 437      FT_Byte*  p   = subheader;
 438      FT_UInt   idx = (FT_UInt)(char_code & 0xFF);
 439      FT_UInt   start, count;
 440      FT_Int    delta;
 441      FT_UInt   offset;
 442
 443
 444      start  = TT_NEXT_USHORT( p );
 445      count  = TT_NEXT_USHORT( p );
 446      delta  = TT_NEXT_SHORT ( p );
 447      offset = TT_PEEK_USHORT( p );
 448
 449      idx -= start;
 450      if ( idx < count && offset != 0 )
 451      {
 452        p  += offset + 2 * idx;
 453        idx = TT_PEEK_USHORT( p );
 454
 455        if ( idx != 0 )
 456          result = (FT_UInt)( idx + delta ) & 0xFFFFU;
 457      }
 458    }
 459    return result;
 460  }
 461
 462
 463  FT_CALLBACK_DEF( FT_UInt32 )
 464  tt_cmap2_char_next( TT_CMap     cmap,
 465                      FT_UInt32  *pcharcode )
 466  {
 467    FT_Byte*   table    = cmap->data;
 468    FT_UInt    gindex   = 0;
 469    FT_UInt32  result   = 0;
 470    FT_UInt32  charcode = *pcharcode + 1;
 471    FT_Byte*   subheader;
 472
 473
 474    while ( charcode < 0x10000UL )
 475    {
 476      subheader = tt_cmap2_get_subheader( table, charcode );
 477      if ( subheader )
 478      {
 479        FT_Byte*  p       = subheader;
 480        FT_UInt   start   = TT_NEXT_USHORT( p );
 481        FT_UInt   count   = TT_NEXT_USHORT( p );
 482        FT_Int    delta   = TT_NEXT_SHORT ( p );
 483        FT_UInt   offset  = TT_PEEK_USHORT( p );
 484        FT_UInt   char_lo = (FT_UInt)( charcode & 0xFF );
 485        FT_UInt   pos, idx;
 486
 487
 488        if ( offset == 0 )
 489          goto Next_SubHeader;
 490
 491        if ( char_lo < start )
 492        {
 493          char_lo = start;
 494          pos     = 0;
 495        }
 496        else
 497          pos = (FT_UInt)( char_lo - start );
 498
 499        p       += offset + pos * 2;
 500        charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo;
 501
 502        for ( ; pos < count; pos++, charcode++ )
 503        {
 504          idx = TT_NEXT_USHORT( p );
 505
 506          if ( idx != 0 )
 507          {
 508            gindex = ( idx + delta ) & 0xFFFFU;
 509            if ( gindex != 0 )
 510            {
 511              result = charcode;
 512              goto Exit;
 513            }
 514          }
 515        }
 516      }
 517
 518      /* jump to next sub-header, i.e. higher byte value */
 519    Next_SubHeader:
 520      charcode = FT_PAD_FLOOR( charcode, 256 ) + 256;
 521    }
 522
 523  Exit:
 524    *pcharcode = result;
 525
 526    return gindex;
 527  }
 528
 529
 530  FT_CALLBACK_DEF( FT_Error )
 531  tt_cmap2_get_info( TT_CMap       cmap,
 532                     TT_CMapInfo  *cmap_info )
 533  {
 534    FT_Byte*  p = cmap->data + 4;
 535
 536
 537    cmap_info->format   = 2;
 538    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
 539
 540    return SFNT_Err_Ok;
 541  }
 542
 543
 544  FT_DEFINE_TT_CMAP(tt_cmap2_class_rec,
 545      sizeof ( TT_CMapRec ),
 546
 547      (FT_CMap_InitFunc)     tt_cmap_init,
 548      (FT_CMap_DoneFunc)     NULL,
 549      (FT_CMap_CharIndexFunc)tt_cmap2_char_index,
 550      (FT_CMap_CharNextFunc) tt_cmap2_char_next,
 551
 552      NULL, NULL, NULL, NULL, NULL
 553    ,
 554    2,
 555    (TT_CMap_ValidateFunc)   tt_cmap2_validate,
 556    (TT_CMap_Info_GetFunc)   tt_cmap2_get_info
 557  )
 558
 559#endif /* TT_CONFIG_CMAP_FORMAT_2 */
 560
 561
 562  /*************************************************************************/
 563  /*************************************************************************/
 564  /*****                                                               *****/
 565  /*****                           FORMAT 4                            *****/
 566  /*****                                                               *****/
 567  /*************************************************************************/
 568  /*************************************************************************/
 569
 570  /*************************************************************************/
 571  /*                                                                       */
 572  /* TABLE OVERVIEW                                                        */
 573  /* --------------                                                        */
 574  /*                                                                       */
 575  /*   NAME          OFFSET         TYPE              DESCRIPTION          */
 576  /*                                                                       */
 577  /*   format        0              USHORT            must be 4            */
 578  /*   length        2              USHORT            table length         */
 579  /*                                                  in bytes             */
 580  /*   language      4              USHORT            Mac language code    */
 581  /*                                                                       */
 582  /*   segCountX2    6              USHORT            2*NUM_SEGS           */
 583  /*   searchRange   8              USHORT            2*(1 << LOG_SEGS)    */
 584  /*   entrySelector 10             USHORT            LOG_SEGS             */
 585  /*   rangeShift    12             USHORT            segCountX2 -         */
 586  /*                                                    searchRange        */
 587  /*                                                                       */
 588  /*   endCount      14             USHORT[NUM_SEGS]  end charcode for     */
 589  /*                                                  each segment; last   */
 590  /*                                                  is 0xFFFF            */
 591  /*                                                                       */
 592  /*   pad           14+NUM_SEGS*2  USHORT            padding              */
 593  /*                                                                       */
 594  /*   startCount    16+NUM_SEGS*2  USHORT[NUM_SEGS]  first charcode for   */
 595  /*                                                  each segment         */
 596  /*                                                                       */
 597  /*   idDelta       16+NUM_SEGS*4  SHORT[NUM_SEGS]   delta for each       */
 598  /*                                                  segment              */
 599  /*   idOffset      16+NUM_SEGS*6  SHORT[NUM_SEGS]   range offset for     */
 600  /*                                                  each segment; can be */
 601  /*                                                  zero                 */
 602  /*                                                                       */
 603  /*   glyphIds      16+NUM_SEGS*8  USHORT[]          array of glyph ID    */
 604  /*                                                  ranges               */
 605  /*                                                                       */
 606  /* Character codes are modelled by a series of ordered (increasing)      */
 607  /* intervals called segments.  Each segment has start and end codes,     */
 608  /* provided by the `startCount' and `endCount' arrays.  Segments must    */
 609  /* not overlap, and the last segment should always contain the value     */
 610  /* 0xFFFF for `endCount'.                                                */
 611  /*                                                                       */
 612  /* The fields `searchRange', `entrySelector' and `rangeShift' are better */
 613  /* ignored (they are traces of over-engineering in the TrueType          */
 614  /* specification).                                                       */
 615  /*                                                                       */
 616  /* Each segment also has a signed `delta', as well as an optional offset */
 617  /* within the `glyphIds' table.                                          */
 618  /*                                                                       */
 619  /* If a segment's idOffset is 0, the glyph index corresponding to any    */
 620  /* charcode within the segment is obtained by adding the value of        */
 621  /* `idDelta' directly to the charcode, modulo 65536.                     */
 622  /*                                                                       */
 623  /* Otherwise, a glyph index is taken from the glyph IDs sub-array for    */
 624  /* the segment, and the value of `idDelta' is added to it.               */
 625  /*                                                                       */
 626  /*                                                                       */
 627  /* Finally, note that a lot of fonts contain an invalid last segment,    */
 628  /* where `start' and `end' are correctly set to 0xFFFF but both `delta'  */
 629  /* and `offset' are incorrect (e.g., `opens___.ttf' which comes with     */
 630  /* OpenOffice.org).  We need special code to deal with them correctly.   */
 631  /*                                                                       */
 632
 633#ifdef TT_CONFIG_CMAP_FORMAT_4
 634
 635  typedef struct  TT_CMap4Rec_
 636  {
 637    TT_CMapRec  cmap;
 638    FT_UInt32   cur_charcode;   /* current charcode */
 639    FT_UInt     cur_gindex;     /* current glyph index */
 640
 641    FT_UInt     num_ranges;
 642    FT_UInt     cur_range;
 643    FT_UInt     cur_start;
 644    FT_UInt     cur_end;
 645    FT_Int      cur_delta;
 646    FT_Byte*    cur_values;
 647
 648  } TT_CMap4Rec, *TT_CMap4;
 649
 650
 651  FT_CALLBACK_DEF( FT_Error )
 652  tt_cmap4_init( TT_CMap4  cmap,
 653                 FT_Byte*  table )
 654  {
 655    FT_Byte*  p;
 656
 657
 658    cmap->cmap.data    = table;
 659
 660    p                  = table + 6;
 661    cmap->num_ranges   = FT_PEEK_USHORT( p ) >> 1;
 662    cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
 663    cmap->cur_gindex   = 0;
 664
 665    return SFNT_Err_Ok;
 666  }
 667
 668
 669  static FT_Int
 670  tt_cmap4_set_range( TT_CMap4  cmap,
 671                      FT_UInt   range_index )
 672  {
 673    FT_Byte*  table = cmap->cmap.data;
 674    FT_Byte*  p;
 675    FT_UInt   num_ranges = cmap->num_ranges;
 676
 677
 678    while ( range_index < num_ranges )
 679    {
 680      FT_UInt  offset;
 681
 682
 683      p             = table + 14 + range_index * 2;
 684      cmap->cur_end = FT_PEEK_USHORT( p );
 685
 686      p              += 2 + num_ranges * 2;
 687      cmap->cur_start = FT_PEEK_USHORT( p );
 688
 689      p              += num_ranges * 2;
 690      cmap->cur_delta = FT_PEEK_SHORT( p );
 691
 692      p     += num_ranges * 2;
 693      offset = FT_PEEK_USHORT( p );
 694
 695      /* some fonts have an incorrect last segment; */
 696      /* we have to catch it                        */
 697      if ( range_index     >= num_ranges - 1 &&
 698           cmap->cur_start == 0xFFFFU        &&
 699           cmap->cur_end   == 0xFFFFU        )
 700      {
 701        TT_Face   face  = (TT_Face)cmap->cmap.cmap.charmap.face;
 702        FT_Byte*  limit = face->cmap_table + face->cmap_size;
 703
 704
 705        if ( offset && p + offset + 2 > limit )
 706        {
 707          cmap->cur_delta = 1;
 708          offset          = 0;
 709        }
 710      }
 711
 712      if ( offset != 0xFFFFU )
 713      {
 714        cmap->cur_values = offset ? p + offset : NULL;
 715        cmap->cur_range  = range_index;
 716        return 0;
 717      }
 718
 719      /* we skip empty segments */
 720      range_index++;
 721    }
 722
 723    return -1;
 724  }
 725
 726
 727  /* search the index of the charcode next to cmap->cur_charcode; */
 728  /* caller should call tt_cmap4_set_range with proper range      */
 729  /* before calling this function                                 */
 730  /*                                                              */
 731  static void
 732  tt_cmap4_next( TT_CMap4  cmap )
 733  {
 734    FT_UInt  charcode;
 735
 736
 737    if ( cmap->cur_charcode >= 0xFFFFUL )
 738      goto Fail;
 739
 740    charcode = (FT_UInt)cmap->cur_charcode + 1;
 741
 742    if ( charcode < cmap->cur_start )
 743      charcode = cmap->cur_start;
 744
 745    for ( ;; )
 746    {
 747      FT_Byte*  values = cmap->cur_values;
 748      FT_UInt   end    = cmap->cur_end;
 749      FT_Int    delta  = cmap->cur_delta;
 750
 751
 752      if ( charcode <= end )
 753      {
 754        if ( values )
 755        {
 756          FT_Byte*  p = values + 2 * ( charcode - cmap->cur_start );
 757
 758
 759          do
 760          {
 761            FT_UInt  gindex = FT_NEXT_USHORT( p );
 762
 763
 764            if ( gindex != 0 )
 765            {
 766              gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU );
 767              if ( gindex != 0 )
 768              {
 769                cmap->cur_charcode = charcode;
 770                cmap->cur_gindex   = gindex;
 771                return;
 772              }
 773            }
 774          } while ( ++charcode <= end );
 775        }
 776        else
 777        {
 778          do
 779          {
 780            FT_UInt  gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU );
 781
 782
 783            if ( gindex != 0 )
 784            {
 785              cmap->cur_charcode = charcode;
 786              cmap->cur_gindex   = gindex;
 787              return;
 788            }
 789          } while ( ++charcode <= end );
 790        }
 791      }
 792
 793      /* we need to find another range */
 794      if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 )
 795        break;
 796
 797      if ( charcode < cmap->cur_start )
 798        charcode = cmap->cur_start;
 799    }
 800
 801  Fail:
 802    cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
 803    cmap->cur_gindex   = 0;
 804  }
 805
 806
 807  FT_CALLBACK_DEF( FT_Error )
 808  tt_cmap4_validate( FT_Byte*      table,
 809                     FT_Validator  valid )
 810  {
 811    FT_Byte*  p      = table + 2;               /* skip format */
 812    FT_UInt   length = TT_NEXT_USHORT( p );
 813    FT_Byte   *ends, *starts, *offsets, *deltas, *glyph_ids;
 814    FT_UInt   num_segs;
 815    FT_Error  error = SFNT_Err_Ok;
 816
 817
 818    if ( length < 16 )
 819      FT_INVALID_TOO_SHORT;
 820
 821    /* in certain fonts, the `length' field is invalid and goes */
 822    /* out of bound.  We try to correct this here...            */
 823    if ( table + length > valid->limit )
 824    {
 825      if ( valid->level >= FT_VALIDATE_TIGHT )
 826        FT_INVALID_TOO_SHORT;
 827
 828      length = (FT_UInt)( valid->limit - table );
 829    }
 830
 831    p        = table + 6;
 832    num_segs = TT_NEXT_USHORT( p );   /* read segCountX2 */
 833
 834    if ( valid->level >= FT_VALIDATE_PARANOID )
 835    {
 836      /* check that we have an even value here */
 837      if ( num_segs & 1 )
 838        FT_INVALID_DATA;
 839    }
 840
 841    num_segs /= 2;
 842
 843    if ( length < 16 + num_segs * 2 * 4 )
 844      FT_INVALID_TOO_SHORT;
 845
 846    /* check the search parameters - even though we never use them */
 847    /*                                                             */
 848    if ( valid->level >= FT_VALIDATE_PARANOID )
 849    {
 850      /* check the values of `searchRange', `entrySelector', `rangeShift' */
 851      FT_UInt  search_range   = TT_NEXT_USHORT( p );
 852      FT_UInt  entry_selector = TT_NEXT_USHORT( p );
 853      FT_UInt  range_shift    = TT_NEXT_USHORT( p );
 854
 855
 856      if ( ( search_range | range_shift ) & 1 )  /* must be even values */
 857        FT_INVALID_DATA;
 858
 859      search_range /= 2;
 860      range_shift  /= 2;
 861
 862      /* `search range' is the greatest power of 2 that is <= num_segs */
 863
 864      if ( search_range                > num_segs                 ||
 865           search_range * 2            < num_segs                 ||
 866           search_range + range_shift != num_segs                 ||
 867           search_range               != ( 1U << entry_selector ) )
 868        FT_INVALID_DATA;
 869    }
 870
 871    ends      = table   + 14;
 872    starts    = table   + 16 + num_segs * 2;
 873    deltas    = starts  + num_segs * 2;
 874    offsets   = deltas  + num_segs * 2;
 875    glyph_ids = offsets + num_segs * 2;
 876
 877    /* check last segment; its end count value must be 0xFFFF */
 878    if ( valid->level >= FT_VALIDATE_PARANOID )
 879    {
 880      p = ends + ( num_segs - 1 ) * 2;
 881      if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
 882        FT_INVALID_DATA;
 883    }
 884
 885    {
 886      FT_UInt   start, end, offset, n;
 887      FT_UInt   last_start = 0, last_end = 0;
 888      FT_Int    delta;
 889      FT_Byte*  p_start   = starts;
 890      FT_Byte*  p_end     = ends;
 891      FT_Byte*  p_delta   = deltas;
 892      FT_Byte*  p_offset  = offsets;
 893
 894
 895      for ( n = 0; n < num_segs; n++ )
 896      {
 897        p      = p_offset;
 898        start  = TT_NEXT_USHORT( p_start );
 899        end    = TT_NEXT_USHORT( p_end );
 900        delta  = TT_NEXT_SHORT( p_delta );
 901        offset = TT_NEXT_USHORT( p_offset );
 902
 903        if ( start > end )
 904          FT_INVALID_DATA;
 905
 906        /* this test should be performed at default validation level; */
 907        /* unfortunately, some popular Asian fonts have overlapping   */
 908        /* ranges in their charmaps                                   */
 909        /*                                                            */
 910        if ( start <= last_end && n > 0 )
 911        {
 912          if ( valid->level >= FT_VALIDATE_TIGHT )
 913            FT_INVALID_DATA;
 914          else
 915          {
 916            /* allow overlapping segments, provided their start points */
 917            /* and end points, respectively, are in ascending order    */
 918            /*                                                         */
 919            if ( last_start > start || last_end > end )
 920              error |= TT_CMAP_FLAG_UNSORTED;
 921            else
 922              error |= TT_CMAP_FLAG_OVERLAPPING;
 923          }
 924        }
 925
 926        if ( offset && offset != 0xFFFFU )
 927        {
 928          p += offset;  /* start of glyph ID array */
 929
 930          /* check that we point within the glyph IDs table only */
 931          if ( valid->level >= FT_VALIDATE_TIGHT )
 932          {
 933            if ( p < glyph_ids                                ||
 934                 p + ( end - start + 1 ) * 2 > table + length )
 935              FT_INVALID_DATA;
 936          }
 937          /* Some fonts handle the last segment incorrectly.  In */
 938          /* theory, 0xFFFF might point to an ordinary glyph --  */
 939          /* a cmap 4 is versatile and could be used for any     */
 940          /* encoding, not only Unicode.  However, reality shows */
 941          /* that far too many fonts are sloppy and incorrectly  */
 942          /* set all fields but `start' and `end' for the last   */
 943          /* segment if it contains only a single character.     */
 944          /*                                                     */
 945          /* We thus omit the test here, delaying it to the      */
 946          /* routines which actually access the cmap.            */
 947          else if ( n != num_segs - 1                       ||
 948                    !( start == 0xFFFFU && end == 0xFFFFU ) )
 949          {
 950            if ( p < glyph_ids                              ||
 951                 p + ( end - start + 1 ) * 2 > valid->limit )
 952              FT_INVALID_DATA;
 953          }
 954
 955          /* check glyph indices within the segment range */
 956          if ( valid->level >= FT_VALIDATE_TIGHT )
 957          {
 958            FT_UInt  i, idx;
 959
 960
 961            for ( i = start; i < end; i++ )
 962            {
 963              idx = FT_NEXT_USHORT( p );
 964              if ( idx != 0 )
 965              {
 966                idx = (FT_UInt)( idx + delta ) & 0xFFFFU;
 967
 968                if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
 969                  FT_INVALID_GLYPH_ID;
 970              }
 971            }
 972          }
 973        }
 974        else if ( offset == 0xFFFFU )
 975        {
 976          /* some fonts (erroneously?) use a range offset of 0xFFFF */
 977          /* to mean missing glyph in cmap table                    */
 978          /*                                                        */
 979          if ( valid->level >= FT_VALIDATE_PARANOID    ||
 980               n != num_segs - 1                       ||
 981               !( start == 0xFFFFU && end == 0xFFFFU ) )
 982            FT_INVALID_DATA;
 983        }
 984
 985        last_start = start;
 986        last_end   = end;
 987      }
 988    }
 989
 990    return error;
 991  }
 992
 993
 994  static FT_UInt
 995  tt_cmap4_char_map_linear( TT_CMap     cmap,
 996                            FT_UInt32*  pcharcode,
 997                            FT_Bool     next )
 998  {
 999    FT_UInt    num_segs2, start, end, offset;
1000    FT_Int     delta;
1001    FT_UInt    i, num_segs;
1002    FT_UInt32  charcode = *pcharcode;
1003    FT_UInt    gindex   = 0;
1004    FT_Byte*   p;
1005
1006
1007    p = cmap->data + 6;
1008    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
1009
1010    num_segs = num_segs2 >> 1;
1011
1012    if ( !num_segs )
1013      return 0;
1014
1015    if ( next )
1016      charcode++;
1017
1018    /* linear search */
1019    for ( ; charcode <= 0xFFFFU; charcode++ )
1020    {
1021      FT_Byte*  q;
1022
1023
1024      p = cmap->data + 14;               /* ends table   */
1025      q = cmap->data + 16 + num_segs2;   /* starts table */
1026
1027      for ( i = 0; i < num_segs; i++ )
1028      {
1029        end   = TT_NEXT_USHORT( p );
1030        start = TT_NEXT_USHORT( q );
1031
1032        if ( charcode >= start && charcode <= end )
1033        {
1034          p       = q - 2 + num_segs2;
1035          delta   = TT_PEEK_SHORT( p );
1036          p      += num_segs2;
1037          offset  = TT_PEEK_USHORT( p );
1038
1039          /* some fonts have an incorrect last segment; */
1040          /* we have to catch it                        */
1041          if ( i >= num_segs - 1                  &&
1042               start == 0xFFFFU && end == 0xFFFFU )
1043          {
1044            TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
1045            FT_Byte*  limit = face->cmap_table + face->cmap_size;
1046
1047
1048            if ( offset && p + offset + 2 > limit )
1049            {
1050              delta  = 1;
1051              offset = 0;
1052            }
1053          }
1054
1055          if ( offset == 0xFFFFU )
1056            continue;
1057
1058          if ( offset )
1059          {
1060            p += offset + ( charcode - start ) * 2;
1061            gindex = TT_PEEK_USHORT( p );
1062            if ( gindex != 0 )
1063              gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
1064          }
1065          else
1066            gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU;
1067
1068          break;
1069        }
1070      }
1071
1072      if ( !next || gindex )
1073        break;
1074    }
1075
1076    if ( next && gindex )
1077      *pcharcode = charcode;
1078
1079    return gindex;
1080  }
1081
1082
1083  static FT_UInt
1084  tt_cmap4_char_map_binary( TT_CMap     cmap,
1085                            FT_UInt32*  pcharcode,
1086                            FT_Bool     next )
1087  {
1088    FT_UInt   num_segs2, start, end, offset;
1089    FT_Int    delta;
1090    FT_UInt   max, min, mid, num_segs;
1091    FT_UInt   charcode = (FT_UInt)*pcharcode;
1092    FT_UInt   gindex   = 0;
1093    FT_Byte*  p;
1094
1095
1096    p = cmap->data + 6;
1097    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
1098
1099    if ( !num_segs2 )
1100      return 0;
1101
1102    num_segs = num_segs2 >> 1;
1103
1104    /* make compiler happy */
1105    mid = num_segs;
1106    end = 0xFFFFU;
1107
1108    if ( next )
1109      charcode++;
1110
1111    min = 0;
1112    max = num_segs;
1113
1114    /* binary search */
1115    while ( min < max )
1116    {
1117      mid    = ( min + max ) >> 1;
1118      p      = cmap->data + 14 + mid * 2;
1119      end    = TT_PEEK_USHORT( p );
1120      p     += 2 + num_segs2;
1121      start  = TT_PEEK_USHORT( p );
1122
1123      if ( charcode < start )
1124        max = mid;
1125      else if ( charcode > end )
1126        min = mid + 1;
1127      else
1128      {
1129        p     += num_segs2;
1130        delta  = TT_PEEK_SHORT( p );
1131        p     += num_segs2;
1132        offset = TT_PEEK_USHORT( p );
1133
1134        /* some fonts have an incorrect last segment; */
1135        /* we have to catch it                        */
1136        if ( mid >= num_segs - 1                &&
1137             start == 0xFFFFU && end == 0xFFFFU )
1138        {
1139          TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
1140          FT_Byte*  limit = face->cmap_table + face->cmap_size;
1141
1142
1143          if ( offset && p + offset + 2 > limit )
1144          {
1145            delta  = 1;
1146            offset = 0;
1147          }
1148        }
1149
1150        /* search the first segment containing `charcode' */
1151        if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING )
1152        {
1153          FT_UInt  i;
1154
1155
1156          /* call the current segment `max' */
1157          max = mid;
1158
1159          if ( offset == 0xFFFFU )
1160            mid = max + 1;
1161
1162          /* search in segments before the current segment */
1163          for ( i = max ; i > 0; i-- )
1164          {
1165            FT_UInt   prev_end;
1166            FT_Byte*  old_p;
1167
1168
1169            old_p    = p;
1170            p        = cmap->data + 14 + ( i - 1 ) * 2;
1171            prev_end = TT_PEEK_USHORT( p );
1172
1173            if ( charcode > prev_end )
1174            {
1175              p = old_p;
1176              break;
1177            }
1178
1179            end    = prev_end;
1180            p     += 2 + num_segs2;
1181            start  = TT_PEEK_USHORT( p );
1182            p     += num_segs2;
1183            delta  = TT_PEEK_SHORT( p );
1184            p     += num_segs2;
1185            offset = TT_PEEK_USHORT( p );
1186
1187            if ( offset != 0xFFFFU )
1188              mid = i - 1;
1189          }
1190
1191          /* no luck */
1192          if ( mid == max + 1 )
1193          {
1194            if ( i != max )
1195            {
1196              p      = cmap->data + 14 + max * 2;
1197              end    = TT_PEEK_USHORT( p );
1198              p     += 2 + num_segs2;
1199              start  = TT_PEEK_USHORT( p );
1200              p     += num_segs2;
1201              delta  = TT_PEEK_SHORT( p );
1202              p     += num_segs2;
1203              offset = TT_PEEK_USHORT( p );
1204            }
1205
1206            mid = max;
1207
1208            /* search in segments after the current segment */
1209            for ( i = max + 1; i < num_segs; i++ )
1210            {
1211              FT_UInt  next_end, next_start;
1212
1213
1214              p          = cmap->data + 14 + i * 2;
1215              next_end   = TT_PEEK_USHORT( p );
1216              p         += 2 + num_segs2;
1217              next_start = TT_PEEK_USHORT( p );
1218
1219              if ( charcode < next_start )
1220                break;
1221
1222              end    = next_end;
1223              start  = next_start;
1224              p     += num_segs2;
1225              delta  = TT_PEEK_SHORT( p );
1226              p     += num_segs2;
1227              offset = TT_PEEK_USHORT( p );
1228
1229              if ( offset != 0xFFFFU )
1230                mid = i;
1231            }
1232            i--;
1233
1234            /* still no luck */
1235            if ( mid == max )
1236            {
1237              mid = i;
1238
1239              break;
1240            }
1241          }
1242
1243          /* end, start, delta, and offset are for the i'th segment */
1244          if ( mid != i )
1245          {
1246            p      = cmap->data + 14 + mid * 2;
1247            end    = TT_PEEK_USHORT( p );
1248            p     += 2 + num_segs2;
1249            start  = TT_PEEK_USHORT( p );
1250            p     += num_segs2;
1251            delta  = TT_PEEK_SHORT( p );
1252            p     += num_segs2;
1253            offset = TT_PEEK_USHORT( p );
1254          }
1255        }
1256        else
1257        {
1258          if ( offset == 0xFFFFU )
1259            break;
1260        }
1261
1262        if ( offset )
1263        {
1264          p += offset + ( charcode - start ) * 2;
1265          gindex = TT_PEEK_USHORT( p );
1266          if ( gindex != 0 )
1267            gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
1268        }
1269        else
1270          gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU;
1271
1272        break;
1273      }
1274    }
1275
1276    if ( next )
1277    {
1278      TT_CMap4  cmap4 = (TT_CMap4)cmap;
1279
1280
1281      /* if `charcode' is not in any segment, then `mid' is */
1282      /* the segment nearest to `charcode'                  */
1283      /*                                                    */
1284
1285      if ( charcode > end )
1286      {
1287        mid++;
1288        if ( mid == num_segs )
1289          return 0;
1290      }
1291
1292      if ( tt_cmap4_set_range( cmap4, mid ) )
1293      {
1294        if ( gindex )
1295          *pcharcode = charcode;
1296      }
1297      else
1298      {
1299        cmap4->cur_charcode = charcode;
1300
1301        if ( gindex )
1302          cmap4->cur_gindex = gindex;
1303        else
1304        {
1305          cmap4->cur_charcode = charcode;
1306          tt_cmap4_next( cmap4 );
1307          gindex = cmap4->cur_gindex;
1308        }
1309
1310        if ( gindex )
1311          *pcharcode = cmap4->cur_charcode;
1312      }
1313    }
1314
1315    return gindex;
1316  }
1317
1318
1319  FT_CALLBACK_DEF( FT_UInt )
1320  tt_cmap4_char_index( TT_CMap    cmap,
1321                       FT_UInt32  char_code )
1322  {
1323    if ( char_code >= 0x10000UL )
1324      return 0;
1325
1326    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
1327      return tt_cmap4_char_map_linear( cmap, &char_code, 0 );
1328    else
1329      return tt_cmap4_char_map_binary( cmap, &char_code, 0 );
1330  }
1331
1332
1333  FT_CALLBACK_DEF( FT_UInt32 )
1334  tt_cmap4_char_next( TT_CMap     cmap,
1335                      FT_UInt32  *pchar_code )
1336  {
1337    FT_UInt  gindex;
1338
1339
1340    if ( *pchar_code >= 0xFFFFU )
1341      return 0;
1342
1343    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
1344      gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 );
1345    else
1346    {
1347      TT_CMap4  cmap4 = (TT_CMap4)cmap;
1348
1349
1350      /* no need to search */
1351      if ( *pchar_code == cmap4->cur_charcode )
1352      {
1353        tt_cmap4_next( cmap4 );
1354        gindex = cmap4->cur_gindex;
1355        if ( gindex )
1356          *pchar_code = cmap4->cur_charcode;
1357      }
1358      else
1359        gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 );
1360    }
1361
1362    return gindex;
1363  }
1364
1365
1366  FT_CALLBACK_DEF( FT_Error )
1367  tt_cmap4_get_info( TT_CMap       cmap,
1368                     TT_CMapInfo  *cmap_info )
1369  {
1370    FT_Byte*  p = cmap->data + 4;
1371
1372
1373    cmap_info->format   = 4;
1374    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
1375
1376    return SFNT_Err_Ok;
1377  }
1378
1379
1380  FT_DEFINE_TT_CMAP(tt_cmap4_class_rec,
1381      sizeof ( TT_CMap4Rec ),
1382      (FT_CMap_InitFunc)     tt_cmap4_init,
1383      (FT_CMap_DoneFunc)     NULL,
1384      (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
1385      (FT_CMap_CharNextFunc) tt_cmap4_char_next,
1386
1387      NULL, NULL, NULL, NULL, NULL
1388    ,
1389    4,
1390    (TT_CMap_ValidateFunc)   tt_cmap4_validate,
1391    (TT_CMap_Info_GetFunc)   tt_cmap4_get_info
1392  )
1393
1394#endif /* TT_CONFIG_CMAP_FORMAT_4 */
1395
1396
1397  /*************************************************************************/
1398  /*************************************************************************/
1399  /*****                                                               *****/
1400  /*****                          FORMAT 6                             *****/
1401  /*****                                                               *****/
1402  /*************************************************************************/
1403  /*************************************************************************/
1404
1405  /*************************************************************************/
1406  /*                                                                       */
1407  /* TABLE OVERVIEW                                                        */
1408  /* --------------                                                        */
1409  /*                                                                       */
1410  /*   NAME        OFFSET          TYPE             DESCRIPTION            */
1411  /*                                                                       */
1412  /*   format       0              USHORT           must be 4              */
1413  /*   length       2              USHORT           table length in bytes  */
1414  /*   language     4              USHORT           Mac language code      */
1415  /*                                                                       */
1416  /*   first        6              USHORT           first segment code     */
1417  /*   count        8              USHORT           segment size in chars  */
1418  /*   glyphIds     10             USHORT[count]    glyph IDs              */
1419  /*                                                                       */
1420  /* A very simplified segment mapping.                                    */
1421  /*                                                                       */
1422
1423#ifdef TT_CONFIG_CMAP_FORMAT_6
1424
1425  FT_CALLBACK_DEF( FT_Error )
1426  tt_cmap6_validate( FT_Byte*      table,
1427                     FT_Validator  valid )
1428  {
1429    FT_Byte*  p;
1430    FT_UInt   length, count;
1431
1432
1433    if ( table + 10 > valid->limit )
1434      FT_INVALID_TOO_SHORT;
1435
1436    p      = table + 2;
1437    length = TT_NEXT_USHORT( p );
1438
1439    p      = table + 8;             /* skip language and start index */
1440    count  = TT_NEXT_USHORT( p );
1441
1442    if ( table + length > valid->limit || length < 10 + count * 2 )
1443      FT_INVALID_TOO_SHORT;
1444
1445    /* check glyph indices */
1446    if ( valid->level >= FT_VALIDATE_TIGHT )
1447    {
1448      FT_UInt  gindex;
1449
1450
1451      for ( ; count > 0; count-- )
1452      {
1453        gindex = TT_NEXT_USHORT( p );
1454        if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
1455          FT_INVALID_GLYPH_ID;
1456      }
1457    }
1458
1459    return SFNT_Err_Ok;
1460  }
1461
1462
1463  FT_CALLBACK_DEF( FT_UInt )
1464  tt_cmap6_char_index( TT_CMap    cmap,
1465                       FT_UInt32  char_code )
1466  {
1467    FT_Byte*  table  = cmap->data;
1468    FT_UInt   result = 0;
1469    FT_Byte*  p      = table + 6;
1470    FT_UInt   start  = TT_NEXT_USHORT( p );
1471    FT_UInt   count  = TT_NEXT_USHORT( p );
1472    FT_UInt   idx    = (FT_UInt)( char_code - start );
1473
1474
1475    if ( idx < count )
1476    {
1477      p += 2 * idx;
1478      result = TT_PEEK_USHORT( p );
1479    }
1480    return result;
1481  }
1482
1483
1484  FT_CALLBACK_DEF( FT_UInt32 )
1485  tt_cmap6_char_next( TT_CMap     cmap,
1486                      FT_UInt32  *pchar_code )
1487  {
1488    FT_Byte*   table     = cmap->data;
1489    FT_UInt32  result    = 0;
1490    FT_UInt32  char_code = *pchar_code + 1;
1491    FT_UInt    gindex    = 0;
1492
1493    FT_Byte*   p         = table + 6;
1494    FT_UInt    start     = TT_NEXT_USHORT( p );
1495    FT_UInt    count     = TT_NEXT_USHORT( p );
1496    FT_UInt    idx;
1497
1498
1499    if ( char_code >= 0x10000UL )
1500      goto Exit;
1501
1502    if ( char_code < start )
1503      char_code = start;
1504
1505    idx = (FT_UInt)( char_code - start );
1506    p  += 2 * idx;
1507
1508    for ( ; idx < count; idx++ )
1509    {
1510      gindex = TT_NEXT_USHORT( p );
1511      if ( gindex != 0 )
1512      {
1513        result = char_code;
1514        break;
1515      }
1516      char_code++;
1517    }
1518
1519  Exit:
1520    *pchar_code = result;
1521    return gindex;
1522  }
1523
1524
1525  FT_CALLBACK_DEF( FT_Error )
1526  tt_cmap6_get_info( TT_CMap       cmap,
1527                     TT_CMapInfo  *cmap_info )
1528  {
1529    FT_Byte*  p = cmap->data + 4;
1530
1531
1532    cmap_info->format   = 6;
1533    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
1534
1535    return SFNT_Err_Ok;
1536  }
1537
1538
1539  FT_DEFINE_TT_CMAP(tt_cmap6_class_rec,
1540      sizeof ( TT_CMapRec ),
1541
1542      (FT_CMap_InitFunc)     tt_cmap_init,
1543      (FT_CMap_DoneFunc)     NULL,
1544      (FT_CMap_CharIndexFunc)tt_cmap6_char_index,
1545      (FT_CMap_Ch

Large files files are truncated, but you can click here to view the full file