source: trunk/poppler/freetype2/src/sfnt/ttcmap.c @ 182

Last change on this file since 182 was 182, checked in by Eugene Romanenko, 15 years ago

freetype update to version 2.3.0

File size: 73.4 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  ttcmap.c                                                               */
4/*                                                                         */
5/*    TrueType character mapping table (cmap) support (body).              */
6/*                                                                         */
7/*  Copyright 2002, 2003, 2004, 2005, 2006, 2007 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
29
30  /*************************************************************************/
31  /*                                                                       */
32  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
33  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
34  /* messages during execution.                                            */
35  /*                                                                       */
36#undef  FT_COMPONENT
37#define FT_COMPONENT  trace_ttcmap
38
39
40#define TT_PEEK_SHORT   FT_PEEK_SHORT
41#define TT_PEEK_USHORT  FT_PEEK_USHORT
42#define TT_PEEK_LONG    FT_PEEK_LONG
43#define TT_PEEK_ULONG   FT_PEEK_ULONG
44
45#define TT_NEXT_SHORT   FT_NEXT_SHORT
46#define TT_NEXT_USHORT  FT_NEXT_USHORT
47#define TT_NEXT_LONG    FT_NEXT_LONG
48#define TT_NEXT_ULONG   FT_NEXT_ULONG
49
50
51  FT_CALLBACK_DEF( FT_Error )
52  tt_cmap_init( TT_CMap   cmap,
53                FT_Byte*  table )
54  {
55    cmap->data = table;
56    return SFNT_Err_Ok;
57  }
58
59
60  /*************************************************************************/
61  /*************************************************************************/
62  /*****                                                               *****/
63  /*****                           FORMAT 0                            *****/
64  /*****                                                               *****/
65  /*************************************************************************/
66  /*************************************************************************/
67
68  /*************************************************************************/
69  /*                                                                       */
70  /* TABLE OVERVIEW                                                        */
71  /* --------------                                                        */
72  /*                                                                       */
73  /*   NAME        OFFSET         TYPE          DESCRIPTION                */
74  /*                                                                       */
75  /*   format      0              USHORT        must be 0                  */
76  /*   length      2              USHORT        table length in bytes      */
77  /*   language    4              USHORT        Mac language code          */
78  /*   glyph_ids   6              BYTE[256]     array of glyph indices     */
79  /*               262                                                     */
80  /*                                                                       */
81
82#ifdef TT_CONFIG_CMAP_FORMAT_0
83
84  FT_CALLBACK_DEF( FT_Error )
85  tt_cmap0_validate( FT_Byte*      table,
86                     FT_Validator  valid )
87  {
88    FT_Byte*  p      = table + 2;
89    FT_UInt   length = TT_NEXT_USHORT( p );
90
91
92    if ( table + length > valid->limit || length < 262 )
93      FT_INVALID_TOO_SHORT;
94
95    /* check glyph indices whenever necessary */
96    if ( valid->level >= FT_VALIDATE_TIGHT )
97    {
98      FT_UInt  n, idx;
99
100
101      p = table + 6;
102      for ( n = 0; n < 256; n++ )
103      {
104        idx = *p++;
105        if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
106          FT_INVALID_GLYPH_ID;
107      }
108    }
109
110    return SFNT_Err_Ok;
111  }
112
113
114  FT_CALLBACK_DEF( FT_UInt )
115  tt_cmap0_char_index( TT_CMap    cmap,
116                       FT_UInt32  char_code )
117  {
118    FT_Byte*  table = cmap->data;
119
120
121    return char_code < 256 ? table[6 + char_code] : 0;
122  }
123
124
125  FT_CALLBACK_DEF( FT_UInt )
126  tt_cmap0_char_next( TT_CMap     cmap,
127                      FT_UInt32  *pchar_code )
128  {
129    FT_Byte*   table    = cmap->data;
130    FT_UInt32  charcode = *pchar_code;
131    FT_UInt32  result   = 0;
132    FT_UInt    gindex   = 0;
133
134
135    table += 6;  /* go to glyph ids */
136    while ( ++charcode < 256 )
137    {
138      gindex = table[charcode];
139      if ( gindex != 0 )
140      {
141        result = charcode;
142        break;
143      }
144    }
145
146    *pchar_code = result;
147    return gindex;
148  }
149
150
151  FT_CALLBACK_DEF( FT_Error )
152  tt_cmap0_get_info( TT_CMap       cmap,
153                     TT_CMapInfo  *cmap_info )
154  {
155    FT_Byte*  p = cmap->data + 4;
156
157
158    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
159
160    return SFNT_Err_Ok;
161  }
162
163
164  FT_CALLBACK_TABLE_DEF
165  const TT_CMap_ClassRec  tt_cmap0_class_rec =
166  {
167    {
168      sizeof ( TT_CMapRec ),
169
170      (FT_CMap_InitFunc)     tt_cmap_init,
171      (FT_CMap_DoneFunc)     NULL,
172      (FT_CMap_CharIndexFunc)tt_cmap0_char_index,
173      (FT_CMap_CharNextFunc) tt_cmap0_char_next
174    },
175    0,
176    (TT_CMap_ValidateFunc)   tt_cmap0_validate,
177    (TT_CMap_Info_GetFunc)   tt_cmap0_get_info
178  };
179
180#endif /* TT_CONFIG_CMAP_FORMAT_0 */
181
182
183  /*************************************************************************/
184  /*************************************************************************/
185  /*****                                                               *****/
186  /*****                          FORMAT 2                             *****/
187  /*****                                                               *****/
188  /***** This is used for certain CJK encodings that encode text in a  *****/
189  /***** mixed 8/16 bits encoding along the following lines:           *****/
190  /*****                                                               *****/
191  /***** * Certain byte values correspond to an 8-bit character code   *****/
192  /*****   (typically in the range 0..127 for ASCII compatibility).    *****/
193  /*****                                                               *****/
194  /***** * Certain byte values signal the first byte of a 2-byte       *****/
195  /*****   character code (but these values are also valid as the      *****/
196  /*****   second byte of a 2-byte character).                         *****/
197  /*****                                                               *****/
198  /***** The following charmap lookup and iteration functions all      *****/
199  /***** assume that the value "charcode" correspond to following:     *****/
200  /*****                                                               *****/
201  /*****   - For one byte characters, "charcode" is simply the         *****/
202  /*****     character code.                                           *****/
203  /*****                                                               *****/
204  /*****   - For two byte characters, "charcode" is the 2-byte         *****/
205  /*****     character code in big endian format.  More exactly:       *****/
206  /*****                                                               *****/
207  /*****       (charcode >> 8)    is the first byte value              *****/
208  /*****       (charcode & 0xFF)  is the second byte value             *****/
209  /*****                                                               *****/
210  /***** Note that not all values of "charcode" are valid according    *****/
211  /***** to these rules, and the function moderately check the         *****/
212  /***** arguments.                                                    *****/
213  /*****                                                               *****/
214  /*************************************************************************/
215  /*************************************************************************/
216
217  /*************************************************************************/
218  /*                                                                       */
219  /* TABLE OVERVIEW                                                        */
220  /* --------------                                                        */
221  /*                                                                       */
222  /*   NAME        OFFSET         TYPE            DESCRIPTION              */
223  /*                                                                       */
224  /*   format      0              USHORT          must be 2                */
225  /*   length      2              USHORT          table length in bytes    */
226  /*   language    4              USHORT          Mac language code        */
227  /*   keys        6              USHORT[256]     sub-header keys          */
228  /*   subs        518            SUBHEAD[NSUBS]  sub-headers array        */
229  /*   glyph_ids   518+NSUB*8     USHORT[]        glyph id array           */
230  /*                                                                       */
231  /* The `keys' table is used to map charcode high-bytes to sub-headers.   */
232  /* The value of `NSUBS' is the number of sub-headers defined in the      */
233  /* table and is computed by finding the maximum of the `keys' table.     */
234  /*                                                                       */
235  /* Note that for any n, `keys[n]' is a byte offset within the `subs'     */
236  /* table, i.e., it is the corresponding sub-header index multiplied      */
237  /* by 8.                                                                 */
238  /*                                                                       */
239  /* Each sub-header has the following format:                             */
240  /*                                                                       */
241  /*   NAME        OFFSET      TYPE            DESCRIPTION                 */
242  /*                                                                       */
243  /*   first       0           USHORT          first valid low-byte        */
244  /*   count       2           USHORT          number of valid low-bytes   */
245  /*   delta       4           SHORT           see below                   */
246  /*   offset      6           USHORT          see below                   */
247  /*                                                                       */
248  /* A sub-header defines, for each high-byte, the range of valid          */
249  /* low-bytes within the charmap.  Note that the range defined by `first' */
250  /* and `count' must be completely included in the interval [0..255]      */
251  /* according to the specification.                                       */
252  /*                                                                       */
253  /* If a character code is contained within a given sub-header, then      */
254  /* mapping it to a glyph index is done as follows:                       */
255  /*                                                                       */
256  /* * The value of `offset' is read.  This is a _byte_ distance from the  */
257  /*   location of the `offset' field itself into a slice of the           */
258  /*   `glyph_ids' table.  Let's call it `slice' (it's a USHORT[] too).    */
259  /*                                                                       */
260  /* * The value `slice[char.lo - first]' is read.  If it is 0, there is   */
261  /*   no glyph for the charcode.  Otherwise, the value of `delta' is      */
262  /*   added to it (modulo 65536) to form a new glyph index.               */
263  /*                                                                       */
264  /* It is up to the validation routine to check that all offsets fall     */
265  /* within the glyph ids table (and not within the `subs' table itself or */
266  /* outside of the CMap).                                                 */
267  /*                                                                       */
268
269#ifdef TT_CONFIG_CMAP_FORMAT_2
270
271  FT_CALLBACK_DEF( FT_Error )
272  tt_cmap2_validate( FT_Byte*      table,
273                     FT_Validator  valid )
274  {
275    FT_Byte*  p      = table + 2;           /* skip format */
276    FT_UInt   length = TT_PEEK_USHORT( p );
277    FT_UInt   n, max_subs;
278    FT_Byte*  keys;                         /* keys table */
279    FT_Byte*  subs;                         /* sub-headers */
280    FT_Byte*  glyph_ids;                    /* glyph id array */
281
282
283    if ( table + length > valid->limit || length < 6 + 512 )
284      FT_INVALID_TOO_SHORT;
285
286    keys = table + 6;
287
288    /* parse keys to compute sub-headers count */
289    p        = keys;
290    max_subs = 0;
291    for ( n = 0; n < 256; n++ )
292    {
293      FT_UInt  idx = TT_NEXT_USHORT( p );
294
295
296      /* value must be multiple of 8 */
297      if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 )
298        FT_INVALID_DATA;
299
300      idx >>= 3;
301
302      if ( idx > max_subs )
303        max_subs = idx;
304    }
305
306    FT_ASSERT( p == table + 518 );
307
308    subs      = p;
309    glyph_ids = subs + (max_subs + 1) * 8;
310    if ( glyph_ids > valid->limit )
311      FT_INVALID_TOO_SHORT;
312
313    /* parse sub-headers */
314    for ( n = 0; n <= max_subs; n++ )
315    {
316      FT_UInt   first_code, code_count, offset;
317      FT_Int    delta;
318      FT_Byte*  ids;
319
320
321      first_code = TT_NEXT_USHORT( p );
322      code_count = TT_NEXT_USHORT( p );
323      delta      = TT_NEXT_SHORT( p );
324      offset     = TT_NEXT_USHORT( p );
325
326      /* check range within 0..255 */
327      if ( valid->level >= FT_VALIDATE_PARANOID )
328      {
329        if ( first_code >= 256 || first_code + code_count > 256 )
330          FT_INVALID_DATA;
331      }
332
333      /* check offset */
334      if ( offset != 0 )
335      {
336        ids = p - 2 + offset;
337        if ( ids < glyph_ids || ids + code_count*2 > table + length )
338          FT_INVALID_OFFSET;
339
340        /* check glyph ids */
341        if ( valid->level >= FT_VALIDATE_TIGHT )
342        {
343          FT_Byte*  limit = p + code_count * 2;
344          FT_UInt   idx;
345
346
347          for ( ; p < limit; )
348          {
349            idx = TT_NEXT_USHORT( p );
350            if ( idx != 0 )
351            {
352              idx = ( idx + delta ) & 0xFFFFU;
353              if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
354                FT_INVALID_GLYPH_ID;
355            }
356          }
357        }
358      }
359    }
360
361    return SFNT_Err_Ok;
362  }
363
364
365  /* return sub header corresponding to a given character code */
366  /* NULL on invalid charcode                                  */
367  static FT_Byte*
368  tt_cmap2_get_subheader( FT_Byte*   table,
369                          FT_UInt32  char_code )
370  {
371    FT_Byte*  result = NULL;
372
373
374    if ( char_code < 0x10000UL )
375    {
376      FT_UInt   char_lo = (FT_UInt)( char_code & 0xFF );
377      FT_UInt   char_hi = (FT_UInt)( char_code >> 8 );
378      FT_Byte*  p       = table + 6;    /* keys table */
379      FT_Byte*  subs    = table + 518;  /* subheaders table */
380      FT_Byte*  sub;
381
382
383      if ( char_hi == 0 )
384      {
385        /* an 8-bit character code -- we use subHeader 0 in this case */
386        /* to test whether the character code is in the charmap       */
387        /*                                                            */
388        sub = subs;  /* jump to first sub-header */
389
390        /* check that the sub-header for this byte is 0, which */
391        /* indicates that it's really a valid one-byte value   */
392        /* Otherwise, return 0                                 */
393        /*                                                     */
394        p += char_lo * 2;
395        if ( TT_PEEK_USHORT( p ) != 0 )
396          goto Exit;
397      }
398      else
399      {
400        /* a 16-bit character code */
401
402        /* jump to key entry  */
403        p  += char_hi * 2;
404        /* jump to sub-header */
405        sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) );
406
407        /* check that the high byte isn't a valid one-byte value */
408        if ( sub == subs )
409          goto Exit;
410      }
411      result = sub;
412    }
413  Exit:
414    return result;
415  }
416
417
418  FT_CALLBACK_DEF( FT_UInt )
419  tt_cmap2_char_index( TT_CMap    cmap,
420                       FT_UInt32  char_code )
421  {
422    FT_Byte*  table   = cmap->data;
423    FT_UInt   result  = 0;
424    FT_Byte*  subheader;
425
426
427    subheader = tt_cmap2_get_subheader( table, char_code );
428    if ( subheader )
429    {
430      FT_Byte*  p   = subheader;
431      FT_UInt   idx = (FT_UInt)(char_code & 0xFF);
432      FT_UInt   start, count;
433      FT_Int    delta;
434      FT_UInt   offset;
435
436
437      start  = TT_NEXT_USHORT( p );
438      count  = TT_NEXT_USHORT( p );
439      delta  = TT_NEXT_SHORT ( p );
440      offset = TT_PEEK_USHORT( p );
441
442      idx -= start;
443      if ( idx < count && offset != 0 )
444      {
445        p  += offset + 2 * idx;
446        idx = TT_PEEK_USHORT( p );
447
448        if ( idx != 0 )
449          result = (FT_UInt)( idx + delta ) & 0xFFFFU;
450      }
451    }
452    return result;
453  }
454
455
456  FT_CALLBACK_DEF( FT_UInt )
457  tt_cmap2_char_next( TT_CMap     cmap,
458                      FT_UInt32  *pcharcode )
459  {
460    FT_Byte*   table    = cmap->data;
461    FT_UInt    gindex   = 0;
462    FT_UInt32  result   = 0;
463    FT_UInt32  charcode = *pcharcode + 1;
464    FT_Byte*   subheader;
465
466
467    while ( charcode < 0x10000UL )
468    {
469      subheader = tt_cmap2_get_subheader( table, charcode );
470      if ( subheader )
471      {
472        FT_Byte*  p       = subheader;
473        FT_UInt   start   = TT_NEXT_USHORT( p );
474        FT_UInt   count   = TT_NEXT_USHORT( p );
475        FT_Int    delta   = TT_NEXT_SHORT ( p );
476        FT_UInt   offset  = TT_PEEK_USHORT( p );
477        FT_UInt   char_lo = (FT_UInt)( charcode & 0xFF );
478        FT_UInt   pos, idx;
479
480
481        if ( offset == 0 )
482          goto Next_SubHeader;
483
484        if ( char_lo < start )
485        {
486          char_lo = start;
487          pos     = 0;
488        }
489        else
490          pos = (FT_UInt)( char_lo - start );
491
492        p       += offset + pos * 2;
493        charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo;
494
495        for ( ; pos < count; pos++, charcode++ )
496        {
497          idx = TT_NEXT_USHORT( p );
498
499          if ( idx != 0 )
500          {
501            gindex = ( idx + delta ) & 0xFFFFU;
502            if ( gindex != 0 )
503            {
504              result = charcode;
505              goto Exit;
506            }
507          }
508        }
509      }
510
511      /* jump to next sub-header, i.e. higher byte value */
512    Next_SubHeader:
513      charcode = FT_PAD_FLOOR( charcode, 256 ) + 256;
514    }
515
516  Exit:
517    *pcharcode = result;
518
519    return gindex;
520  }
521
522
523  FT_CALLBACK_DEF( FT_Error )
524  tt_cmap2_get_info( TT_CMap       cmap,
525                     TT_CMapInfo  *cmap_info )
526  {
527    FT_Byte*  p = cmap->data + 4;
528
529
530    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
531
532    return SFNT_Err_Ok;
533  }
534
535
536  FT_CALLBACK_TABLE_DEF
537  const TT_CMap_ClassRec  tt_cmap2_class_rec =
538  {
539    {
540      sizeof ( TT_CMapRec ),
541
542      (FT_CMap_InitFunc)     tt_cmap_init,
543      (FT_CMap_DoneFunc)     NULL,
544      (FT_CMap_CharIndexFunc)tt_cmap2_char_index,
545      (FT_CMap_CharNextFunc) tt_cmap2_char_next
546    },
547    2,
548    (TT_CMap_ValidateFunc)   tt_cmap2_validate,
549    (TT_CMap_Info_GetFunc)   tt_cmap2_get_info
550  };
551
552#endif /* TT_CONFIG_CMAP_FORMAT_2 */
553
554
555  /*************************************************************************/
556  /*************************************************************************/
557  /*****                                                               *****/
558  /*****                           FORMAT 4                            *****/
559  /*****                                                               *****/
560  /*************************************************************************/
561  /*************************************************************************/
562
563  /*************************************************************************/
564  /*                                                                       */
565  /* TABLE OVERVIEW                                                        */
566  /* --------------                                                        */
567  /*                                                                       */
568  /*   NAME          OFFSET         TYPE              DESCRIPTION          */
569  /*                                                                       */
570  /*   format        0              USHORT            must be 4            */
571  /*   length        2              USHORT            table length         */
572  /*                                                  in bytes             */
573  /*   language      4              USHORT            Mac language code    */
574  /*                                                                       */
575  /*   segCountX2    6              USHORT            2*NUM_SEGS           */
576  /*   searchRange   8              USHORT            2*(1 << LOG_SEGS)    */
577  /*   entrySelector 10             USHORT            LOG_SEGS             */
578  /*   rangeShift    12             USHORT            segCountX2 -         */
579  /*                                                    searchRange        */
580  /*                                                                       */
581  /*   endCount      14             USHORT[NUM_SEGS]  end charcode for     */
582  /*                                                  each segment; last   */
583  /*                                                  is 0xFFFF            */
584  /*                                                                       */
585  /*   pad           14+NUM_SEGS*2  USHORT            padding              */
586  /*                                                                       */
587  /*   startCount    16+NUM_SEGS*2  USHORT[NUM_SEGS]  first charcode for   */
588  /*                                                  each segment         */
589  /*                                                                       */
590  /*   idDelta       16+NUM_SEGS*4  SHORT[NUM_SEGS]   delta for each       */
591  /*                                                  segment              */
592  /*   idOffset      16+NUM_SEGS*6  SHORT[NUM_SEGS]   range offset for     */
593  /*                                                  each segment; can be */
594  /*                                                  zero                 */
595  /*                                                                       */
596  /*   glyphIds      16+NUM_SEGS*8  USHORT[]          array of glyph id    */
597  /*                                                  ranges               */
598  /*                                                                       */
599  /* Character codes are modelled by a series of ordered (increasing)      */
600  /* intervals called segments.  Each segment has start and end codes,     */
601  /* provided by the `startCount' and `endCount' arrays.  Segments must    */
602  /* not be overlapping and the last segment should always contain the     */
603  /* `0xFFFF' endCount.                                                    */
604  /*                                                                       */
605  /* The fields `searchRange', `entrySelector' and `rangeShift' are better */
606  /* ignored (they are traces of over-engineering in the TrueType          */
607  /* specification).                                                       */
608  /*                                                                       */
609  /* Each segment also has a signed `delta', as well as an optional offset */
610  /* within the `glyphIds' table.                                          */
611  /*                                                                       */
612  /* If a segment's idOffset is 0, the glyph index corresponding to any    */
613  /* charcode within the segment is obtained by adding the value of        */
614  /* `idDelta' directly to the charcode, modulo 65536.                     */
615  /*                                                                       */
616  /* Otherwise, a glyph index is taken from the glyph ids sub-array for    */
617  /* the segment, and the value of `idDelta' is added to it.               */
618  /*                                                                       */
619  /*                                                                       */
620  /* Finally, note that certain fonts contain invalid charmaps that        */
621  /* contain end=0xFFFF, start=0xFFFF, delta=0x0001, offset=0xFFFF at the  */
622  /* of their charmaps (e.g. opens___.ttf which comes with OpenOffice.org) */
623  /* we need special code to deal with them correctly...                   */
624  /*                                                                       */
625
626#ifdef TT_CONFIG_CMAP_FORMAT_4
627
628  typedef struct  TT_CMap4Rec_
629  {
630    TT_CMapRec  cmap;
631    FT_UInt32   cur_charcode;   /* current charcode */
632    FT_UInt     cur_gindex;     /* current glyph index */
633
634    FT_UInt     num_ranges;
635    FT_UInt     cur_range;
636    FT_UInt     cur_start;
637    FT_UInt     cur_end;
638    FT_Int      cur_delta;
639    FT_Byte*    cur_values;
640
641  } TT_CMap4Rec, *TT_CMap4;
642
643
644  FT_CALLBACK_DEF( FT_Error )
645  tt_cmap4_init( TT_CMap4  cmap,
646                 FT_Byte*  table )
647  {
648    FT_Byte*  p;
649
650
651    cmap->cmap.data    = table;
652
653    p                  = table + 6;
654    cmap->num_ranges   = FT_PEEK_USHORT( p ) >> 1;
655    cmap->cur_charcode = 0xFFFFFFFFUL;
656    cmap->cur_gindex   = 0;
657
658    return SFNT_Err_Ok;
659  }
660
661
662  static FT_Int
663  tt_cmap4_set_range( TT_CMap4  cmap,
664                      FT_UInt   range_index )
665  {
666    FT_Byte*  table = cmap->cmap.data;
667    FT_Byte*  p;
668    FT_UInt   num_ranges = cmap->num_ranges;
669
670
671    while ( range_index < num_ranges )
672    {
673      FT_UInt  offset;
674
675
676      p             = table + 14 + range_index * 2;
677      cmap->cur_end = FT_PEEK_USHORT( p );
678
679      p              += 2 + num_ranges * 2;
680      cmap->cur_start = FT_PEEK_USHORT( p );
681
682      p              += num_ranges * 2;
683      cmap->cur_delta = FT_PEEK_SHORT( p );
684
685      p     += num_ranges * 2;
686      offset = FT_PEEK_USHORT( p );
687
688      if ( offset != 0xFFFFU )
689      {
690        cmap->cur_values = offset ? p + offset : NULL;
691        cmap->cur_range  = range_index;
692        return 0;
693      }
694
695      /* we skip empty segments */
696      range_index++;
697    }
698
699    return -1;
700  }
701
702
703  /* search the index of the charcode next to cmap->cur_charcode; */
704  /* caller should call tt_cmap4_set_range with proper range      */
705  /* before calling this function                                 */
706  /*                                                              */
707  static void
708  tt_cmap4_next( TT_CMap4  cmap )
709  {
710    FT_UInt  charcode;
711
712
713    if ( cmap->cur_charcode >= 0xFFFFUL )
714      goto Fail;
715
716    charcode = cmap->cur_charcode + 1;
717
718    if ( charcode < cmap->cur_start )
719      charcode = cmap->cur_start;
720
721    for ( ;; )
722    {
723      FT_Byte*  values = cmap->cur_values;
724      FT_UInt   end    = cmap->cur_end;
725      FT_Int    delta  = cmap->cur_delta;
726
727
728      if ( charcode <= end )
729      {
730        if ( values )
731        {
732          FT_Byte*  p = values + 2 * ( charcode - cmap->cur_start );
733
734
735          do
736          {
737            FT_UInt  gindex = FT_NEXT_USHORT( p );
738
739
740            if ( gindex != 0 )
741            {
742              gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU );
743              if ( gindex != 0 )
744              {
745                cmap->cur_charcode = charcode;
746                cmap->cur_gindex   = gindex;
747                return;
748              }
749            }
750          } while ( ++charcode <= end );
751        }
752        else
753        {
754          do
755          {
756            FT_UInt  gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU );
757
758
759            if ( gindex != 0 )
760            {
761              cmap->cur_charcode = charcode;
762              cmap->cur_gindex   = gindex;
763              return;
764            }
765          } while ( ++charcode <= end );
766        }
767      }
768
769      /* we need to find another range */
770      if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 )
771        break;
772
773      if ( charcode < cmap->cur_start )
774        charcode = cmap->cur_start;
775    }
776
777  Fail:
778    cmap->cur_charcode = 0xFFFFFFFFUL;
779    cmap->cur_gindex   = 0;
780  }
781
782
783  FT_CALLBACK_DEF( FT_Error )
784  tt_cmap4_validate( FT_Byte*      table,
785                     FT_Validator  valid )
786  {
787    FT_Byte*  p      = table + 2;               /* skip format */
788    FT_UInt   length = TT_NEXT_USHORT( p );
789    FT_Byte   *ends, *starts, *offsets, *deltas, *glyph_ids;
790    FT_UInt   num_segs;
791    FT_Error  error = SFNT_Err_Ok;
792
793
794    if ( length < 16 )
795      FT_INVALID_TOO_SHORT;
796
797    /* in certain fonts, the `length' field is invalid and goes */
798    /* out of bound.  We try to correct this here...            */
799    if ( table + length > valid->limit )
800    {
801      if ( valid->level >= FT_VALIDATE_TIGHT )
802        FT_INVALID_TOO_SHORT;
803
804      length = (FT_UInt)( valid->limit - table );
805    }
806
807    p        = table + 6;
808    num_segs = TT_NEXT_USHORT( p );   /* read segCountX2 */
809
810    if ( valid->level >= FT_VALIDATE_PARANOID )
811    {
812      /* check that we have an even value here */
813      if ( num_segs & 1 )
814        FT_INVALID_DATA;
815    }
816
817    num_segs /= 2;
818
819    if ( length < 16 + num_segs * 2 * 4 )
820      FT_INVALID_TOO_SHORT;
821
822    /* check the search parameters - even though we never use them */
823    /*                                                             */
824    if ( valid->level >= FT_VALIDATE_PARANOID )
825    {
826      /* check the values of 'searchRange', 'entrySelector', 'rangeShift' */
827      FT_UInt  search_range   = TT_NEXT_USHORT( p );
828      FT_UInt  entry_selector = TT_NEXT_USHORT( p );
829      FT_UInt  range_shift    = TT_NEXT_USHORT( p );
830
831
832      if ( ( search_range | range_shift ) & 1 )  /* must be even values */
833        FT_INVALID_DATA;
834
835      search_range /= 2;
836      range_shift  /= 2;
837
838      /* `search range' is the greatest power of 2 that is <= num_segs */
839
840      if ( search_range                > num_segs                 ||
841           search_range * 2            < num_segs                 ||
842           search_range + range_shift != num_segs                 ||
843           search_range               != ( 1U << entry_selector ) )
844        FT_INVALID_DATA;
845    }
846
847    ends      = table   + 14;
848    starts    = table   + 16 + num_segs * 2;
849    deltas    = starts  + num_segs * 2;
850    offsets   = deltas  + num_segs * 2;
851    glyph_ids = offsets + num_segs * 2;
852
853    /* check last segment, its end count must be FFFF */
854    if ( valid->level >= FT_VALIDATE_PARANOID )
855    {
856      p = ends + ( num_segs - 1 ) * 2;
857      if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
858        FT_INVALID_DATA;
859    }
860
861    {
862      FT_UInt  start, end, offset, n;
863      FT_UInt  last_start = 0, last_end = 0;
864      FT_Int   delta;
865      FT_Byte*  p_start   = starts;
866      FT_Byte*  p_end     = ends;
867      FT_Byte*  p_delta   = deltas;
868      FT_Byte*  p_offset  = offsets;
869
870
871      for ( n = 0; n < num_segs; n++ )
872      {
873        p      = p_offset;
874        start  = TT_NEXT_USHORT( p_start );
875        end    = TT_NEXT_USHORT( p_end );
876        delta  = TT_NEXT_SHORT( p_delta );
877        offset = TT_NEXT_USHORT( p_offset );
878
879        if ( start > end )
880          FT_INVALID_DATA;
881
882        /* this test should be performed at default validation level;  */
883        /* unfortunately, some popular Asian fonts present overlapping */
884        /* ranges in their charmaps                                    */
885        /*                                                             */
886        if ( start <= last_end && n > 0 )
887        {
888          if ( valid->level >= FT_VALIDATE_TIGHT )
889            FT_INVALID_DATA;
890          else
891          {
892            /* allow overlapping segments, provided their start points */
893            /* and end points, respectively, are in ascending order.   */
894            /*                                                         */
895            if ( last_start > start || last_end > end )
896              error |= TT_CMAP_FLAG_UNSORTED;
897            else
898              error |= TT_CMAP_FLAG_OVERLAPPING;
899          }
900        }
901
902        if ( offset && offset != 0xFFFFU )
903        {
904          p += offset;  /* start of glyph id array */
905
906          /* check that we point within the glyph ids table only */
907          if ( valid->level >= FT_VALIDATE_TIGHT )
908          {
909            if ( p < glyph_ids                                ||
910                 p + ( end - start + 1 ) * 2 > table + length )
911              FT_INVALID_DATA;
912          }
913          else
914          {
915            if ( p < glyph_ids                              ||
916                 p + ( end - start + 1 ) * 2 > valid->limit )
917              FT_INVALID_DATA;
918          }
919
920          /* check glyph indices within the segment range */
921          if ( valid->level >= FT_VALIDATE_TIGHT )
922          {
923            FT_UInt  i, idx;
924
925
926            for ( i = start; i < end; i++ )
927            {
928              idx = FT_NEXT_USHORT( p );
929              if ( idx != 0 )
930              {
931                idx = (FT_UInt)( idx + delta ) & 0xFFFFU;
932
933                if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
934                  FT_INVALID_GLYPH_ID;
935              }
936            }
937          }
938        }
939        else if ( offset == 0xFFFFU )
940        {
941          /* Some fonts (erroneously?) use a range offset of 0xFFFF */
942          /* to mean missing glyph in cmap table                    */
943          /*                                                        */
944          if ( valid->level >= FT_VALIDATE_PARANOID                     ||
945               n != num_segs - 1                                        ||
946               !( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) )
947            FT_INVALID_DATA;
948        }
949
950        last_start = start;
951        last_end   = end;
952      }
953    }
954
955    return error;
956  }
957
958
959  static FT_UInt
960  tt_cmap4_char_map_linear( TT_CMap   cmap,
961                            FT_UInt*  pcharcode,
962                            FT_Bool   next )
963  {
964    FT_UInt    num_segs2, start, end, offset;
965    FT_Int     delta;
966    FT_UInt    i, num_segs;
967    FT_UInt32  charcode = *pcharcode;
968    FT_UInt    gindex   = 0;
969    FT_Byte*   p;
970
971
972    p = cmap->data + 6;
973    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
974
975    num_segs = num_segs2 >> 1;
976
977    if ( !num_segs )
978      return 0;
979
980    if ( next )
981      charcode++;
982
983    /* linear search */
984    for ( ; charcode <= 0xFFFFU; charcode++ )
985    {
986      FT_Byte*  q;
987
988
989      p = cmap->data + 14;               /* ends table   */
990      q = cmap->data + 16 + num_segs2;   /* starts table */
991
992      for ( i = 0; i < num_segs; i++ )
993      {
994        end   = TT_NEXT_USHORT( p );
995        start = TT_NEXT_USHORT( q );
996
997        if ( charcode >= start && charcode <= end )
998        {
999          p       = q - 2 + num_segs2;
1000          delta   = TT_PEEK_SHORT( p );
1001          p      += num_segs2;
1002          offset  = TT_PEEK_USHORT( p );
1003
1004          if ( offset == 0xFFFFU )
1005            continue;
1006
1007          if ( offset )
1008          {
1009            p += offset + ( charcode - start ) * 2;
1010            gindex = TT_PEEK_USHORT( p );
1011            if ( gindex != 0 )
1012              gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
1013          }
1014          else
1015            gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU;
1016
1017          break;
1018        }
1019      }
1020
1021      if ( !next || gindex )
1022        break;
1023    }
1024
1025    if ( next && gindex )
1026      *pcharcode = charcode;
1027
1028    return gindex;
1029  }
1030
1031
1032  static FT_UInt
1033  tt_cmap4_char_map_binary( TT_CMap   cmap,
1034                            FT_UInt*  pcharcode,
1035                            FT_Bool   next )
1036  {
1037    FT_UInt   num_segs2, start, end, offset;
1038    FT_Int    delta;
1039    FT_UInt   max, min, mid, num_segs;
1040    FT_UInt   charcode = *pcharcode;
1041    FT_UInt   gindex   = 0;
1042    FT_Byte*  p;
1043
1044
1045    p = cmap->data + 6;
1046    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
1047
1048    if ( !num_segs2 )
1049      return 0;
1050
1051    num_segs = num_segs2 >> 1;
1052
1053    /* make compiler happy */
1054    mid = num_segs;
1055    end = 0xFFFFU;
1056
1057    if ( next )
1058      charcode++;
1059
1060    min = 0;
1061    max = num_segs;
1062
1063    /* binary search */
1064    while ( min < max )
1065    {
1066      mid    = ( min + max ) >> 1;
1067      p      = cmap->data + 14 + mid * 2;
1068      end    = TT_PEEK_USHORT( p );
1069      p     += 2 + num_segs2;
1070      start  = TT_PEEK_USHORT( p );
1071
1072      if ( charcode < start )
1073        max = mid;
1074      else if ( charcode > end )
1075        min = mid + 1;
1076      else
1077      {
1078        p     += num_segs2;
1079        delta  = TT_PEEK_SHORT( p );
1080        p     += num_segs2;
1081        offset = TT_PEEK_USHORT( p );
1082
1083        /* search the first segment containing `charcode' */
1084        if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING )
1085        {
1086          FT_UInt  i;
1087
1088
1089          /* call the current segment `max' */
1090          max = mid;
1091
1092          if ( offset == 0xFFFFU )
1093            mid = max + 1;
1094
1095          /* search in segments before the current segment */
1096          for ( i = max ; i > 0; i-- )
1097          {
1098            FT_UInt   prev_end;
1099            FT_Byte*  old_p;
1100
1101
1102            old_p    = p;
1103            p        = cmap->data + 14 + ( i - 1 ) * 2;
1104            prev_end = TT_PEEK_USHORT( p );
1105
1106            if ( charcode > prev_end )
1107            {
1108              p = old_p;
1109              break;
1110            }
1111
1112            end    = prev_end;
1113            p     += 2 + num_segs2;
1114            start  = TT_PEEK_USHORT( p );
1115            p     += num_segs2;
1116            delta  = TT_PEEK_SHORT( p );
1117            p     += num_segs2;
1118            offset = TT_PEEK_USHORT( p );
1119
1120            if ( offset != 0xFFFFU )
1121              mid = i - 1;
1122          }
1123
1124          /* no luck */
1125          if ( mid == max + 1 )
1126          {
1127            if ( i != max )
1128            {
1129              p      = cmap->data + 14 + max * 2;
1130              end    = TT_PEEK_USHORT( p );
1131              p     += 2 + num_segs2;
1132              start  = TT_PEEK_USHORT( p );
1133              p     += num_segs2;
1134              delta  = TT_PEEK_SHORT( p );
1135              p     += num_segs2;
1136              offset = TT_PEEK_USHORT( p );
1137            }
1138
1139            mid = max;
1140
1141            /* search in segments after the current segment */
1142            for ( i = max + 1; i < num_segs; i++ )
1143            {
1144              FT_UInt  next_end, next_start;
1145
1146
1147              p          = cmap->data + 14 + i * 2;
1148              next_end   = TT_PEEK_USHORT( p );
1149              p         += 2 + num_segs2;
1150              next_start = TT_PEEK_USHORT( p );
1151
1152              if ( charcode < next_start )
1153                break;
1154
1155              end    = next_end;
1156              start  = next_start;
1157              p     += num_segs2;
1158              delta  = TT_PEEK_SHORT( p );
1159              p     += num_segs2;
1160              offset = TT_PEEK_USHORT( p );
1161
1162              if ( offset != 0xFFFFU )
1163                mid = i;
1164            }
1165            i--;
1166
1167            /* still no luck */
1168            if ( mid == max )
1169            {
1170              mid = i;
1171
1172              break;
1173            }
1174          }
1175
1176          /* end, start, delta, and offset are for the i'th segment */
1177          if ( mid != i )
1178          {
1179            p      = cmap->data + 14 + mid * 2;
1180            end    = TT_PEEK_USHORT( p );
1181            p     += 2 + num_segs2;
1182            start  = TT_PEEK_USHORT( p );
1183            p     += num_segs2;
1184            delta  = TT_PEEK_SHORT( p );
1185            p     += num_segs2;
1186            offset = TT_PEEK_USHORT( p );
1187          }
1188        }
1189        else
1190        {
1191          if ( offset == 0xFFFFU )
1192            break;
1193        }
1194
1195        if ( offset )
1196        {
1197          p += offset + ( charcode - start ) * 2;
1198          gindex = TT_PEEK_USHORT( p );
1199          if ( gindex != 0 )
1200            gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
1201        }
1202        else
1203          gindex = (FT_UInt)( charcode + delta ) & 0xFFFFU;
1204
1205        break;
1206      }
1207    }
1208
1209    if ( next )
1210    {
1211      TT_CMap4  cmap4 = (TT_CMap4)cmap;
1212
1213
1214      /* if `charcode' is not in any segment, then `mid' is */
1215      /* the segment nearest to `charcode'                  */
1216      /*                                                    */
1217
1218      if ( charcode > end )
1219      {
1220        mid++;
1221        if ( mid == num_segs )
1222          return 0;
1223      }
1224
1225      if ( tt_cmap4_set_range( cmap4, mid ) )
1226      {
1227        if ( gindex )
1228          *pcharcode = charcode;
1229      }
1230      else
1231      {
1232        cmap4->cur_charcode = charcode;
1233
1234        if ( gindex )
1235          cmap4->cur_gindex = gindex;
1236        else
1237        {
1238          cmap4->cur_charcode = charcode;
1239          tt_cmap4_next( cmap4 );
1240          gindex = cmap4->cur_gindex;
1241        }
1242
1243        if ( gindex )
1244          *pcharcode = cmap4->cur_charcode;
1245      }
1246    }
1247
1248    return gindex;
1249  }
1250
1251
1252  FT_CALLBACK_DEF( FT_UInt )
1253  tt_cmap4_char_index( TT_CMap    cmap,
1254                       FT_UInt32  char_code )
1255  {
1256    if ( char_code >= 0x10000UL )
1257      return 0;
1258
1259    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
1260      return tt_cmap4_char_map_linear( cmap, &char_code, 0 );
1261    else
1262      return tt_cmap4_char_map_binary( cmap, &char_code, 0 );
1263  }
1264
1265
1266  FT_CALLBACK_DEF( FT_UInt )
1267  tt_cmap4_char_next( TT_CMap     cmap,
1268                      FT_UInt32  *pchar_code )
1269  {
1270    FT_UInt  gindex;
1271
1272
1273    if ( *pchar_code >= 0xFFFFU )
1274      return 0;
1275
1276    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
1277      gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 );
1278    else
1279    {
1280      TT_CMap4  cmap4 = (TT_CMap4)cmap;
1281
1282
1283      /* no need to search */
1284      if ( *pchar_code == cmap4->cur_charcode )
1285      {
1286        tt_cmap4_next( cmap4 );
1287        gindex = cmap4->cur_gindex;
1288        if ( gindex )
1289          *pchar_code = cmap4->cur_charcode;
1290      }
1291      else
1292        gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 );
1293    }
1294
1295    return gindex;
1296  }
1297
1298
1299  FT_CALLBACK_DEF( FT_Error )
1300  tt_cmap4_get_info( TT_CMap       cmap,
1301                     TT_CMapInfo  *cmap_info )
1302  {
1303    FT_Byte*  p = cmap->data + 4;
1304
1305
1306    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
1307
1308    return SFNT_Err_Ok;
1309  }
1310
1311
1312  FT_CALLBACK_TABLE_DEF
1313  const TT_CMap_ClassRec  tt_cmap4_class_rec =
1314  {
1315    {
1316      sizeof ( TT_CMap4Rec ),
1317      (FT_CMap_InitFunc)     tt_cmap4_init,
1318      (FT_CMap_DoneFunc)     NULL,
1319      (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
1320      (FT_CMap_CharNextFunc) tt_cmap4_char_next
1321    },
1322    4,
1323    (TT_CMap_ValidateFunc)   tt_cmap4_validate,
1324    (TT_CMap_Info_GetFunc)   tt_cmap4_get_info
1325  };
1326
1327#endif /* TT_CONFIG_CMAP_FORMAT_4 */
1328
1329
1330  /*************************************************************************/
1331  /*************************************************************************/
1332  /*****                                                               *****/
1333  /*****                          FORMAT 6                             *****/
1334  /*****                                                               *****/
1335  /*************************************************************************/
1336  /*************************************************************************/
1337
1338  /*************************************************************************/
1339  /*                                                                       */
1340  /* TABLE OVERVIEW                                                        */
1341  /* --------------                                                        */
1342  /*                                                                       */
1343  /*   NAME        OFFSET          TYPE             DESCRIPTION            */
1344  /*                                                                       */
1345  /*   format       0              USHORT           must be 4              */
1346  /*   length       2              USHORT           table length in bytes  */
1347  /*   language     4              USHORT           Mac language code      */
1348  /*                                                                       */
1349  /*   first        6              USHORT           first segment code     */
1350  /*   count        8              USHORT           segment size in chars  */
1351  /*   glyphIds     10             USHORT[count]    glyph ids              */
1352  /*                                                                       */
1353  /* A very simplified segment mapping.                                    */
1354  /*                                                                       */
1355
1356#ifdef TT_CONFIG_CMAP_FORMAT_6
1357
1358  FT_CALLBACK_DEF( FT_Error )
1359  tt_cmap6_validate( FT_Byte*      table,
1360                     FT_Validator  valid )
1361  {
1362    FT_Byte*  p;
1363    FT_UInt   length, count;
1364
1365
1366    if ( table + 10 > valid->limit )
1367      FT_INVALID_TOO_SHORT;
1368
1369    p      = table + 2;
1370    length = TT_NEXT_USHORT( p );
1371
1372    p      = table + 8;             /* skip language and start index */
1373    count  = TT_NEXT_USHORT( p );
1374
1375    if ( table + length > valid->limit || length < 10 + count * 2 )
1376      FT_INVALID_TOO_SHORT;
1377
1378    /* check glyph indices */
1379    if ( valid->level >= FT_VALIDATE_TIGHT )
1380    {
1381      FT_UInt  gindex;
1382
1383
1384      for ( ; count > 0; count-- )
1385      {
1386        gindex = TT_NEXT_USHORT( p );
1387        if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
1388          FT_INVALID_GLYPH_ID;
1389      }
1390    }
1391
1392    return SFNT_Err_Ok;
1393  }
1394
1395
1396  FT_CALLBACK_DEF( FT_UInt )
1397  tt_cmap6_char_index( TT_CMap    cmap,
1398                       FT_UInt32  char_code )
1399  {
1400    FT_Byte*  table  = cmap->data;
1401    FT_UInt   result = 0;
1402    FT_Byte*  p      = table + 6;
1403    FT_UInt   start  = TT_NEXT_USHORT( p );
1404    FT_UInt   count  = TT_NEXT_USHORT( p );
1405    FT_UInt   idx    = (FT_UInt)( char_code - start );
1406
1407
1408    if ( idx < count )
1409    {
1410      p += 2 * idx;
1411      result = TT_PEEK_USHORT( p );
1412    }
1413    return result;
1414  }
1415
1416
1417  FT_CALLBACK_DEF( FT_UInt )
1418  tt_cmap6_char_next( TT_CMap     cmap,
1419                      FT_UInt32  *pchar_code )
1420  {
1421    FT_Byte*   table     = cmap->data;
1422    FT_UInt32  result    = 0;
1423    FT_UInt32  char_code = *pchar_code + 1;
1424    FT_UInt    gindex    = 0;
1425
1426    FT_Byte*   p         = table + 6;
1427    FT_UInt    start     = TT_NEXT_USHORT( p );
1428    FT_UInt    count     = TT_NEXT_USHORT( p );
1429    FT_UInt    idx;
1430
1431
1432    if ( char_code >= 0x10000UL )
1433      goto Exit;
1434
1435    if ( char_code < start )
1436      char_code = start;
1437
1438    idx = (FT_UInt)( char_code - start );
1439    p  += 2 * idx;
1440
1441    for ( ; idx < count; idx++ )
1442    {
1443      gindex = TT_NEXT_USHORT( p );
1444      if ( gindex != 0 )
1445      {
1446        result = char_code;
1447        break;
1448      }
1449      char_code++;
1450    }
1451
1452  Exit:
1453    *pchar_code = result;
1454    return gindex;
1455  }
1456
1457
1458  FT_CALLBACK_DEF( FT_Error )
1459  tt_cmap6_get_info( TT_CMap       cmap,
1460                     TT_CMapInfo  *cmap_info )
1461  {
1462    FT_Byte*  p = cmap->data + 4;
1463
1464
1465    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
1466
1467    return SFNT_Err_Ok;
1468  }
1469
1470
1471  FT_CALLBACK_TABLE_DEF
1472  const TT_CMap_ClassRec  tt_cmap6_class_rec =
1473  {
1474    {
1475      sizeof ( TT_CMapRec ),
1476
1477      (FT_CMap_InitFunc)     tt_cmap_init,
1478      (FT_CMap_DoneFunc)     NULL,
1479      (FT_CMap_CharIndexFunc)tt_cmap6_char_index,
1480      (FT_CMap_CharNextFunc) tt_cmap6_char_next
1481    },
1482    6,
1483    (TT_CMap_ValidateFunc)   tt_cmap6_validate,
1484    (TT_CMap_Info_GetFunc)   tt_cmap6_get_info
1485  };
1486
1487#endif /* TT_CONFIG_CMAP_FORMAT_6 */
1488
1489
1490  /*************************************************************************/
1491  /*************************************************************************/
1492  /*****                                                               *****/
1493  /*****                          FORMAT 8                             *****/
1494  /*****                                                               *****/
1495  /***** It's hard to completely understand what the OpenType spec     *****/
1496  /***** says about this format, but here is my conclusion.            *****/
1497  /*****                                                               *****/
1498  /***** The purpose of this format is to easily map UTF-16 text to    *****/
1499  /***** glyph indices.  Basically, the `char_code' must be in one of  *****/
1500  /***** the following formats:                                        *****/
1501  /*****                                                               *****/
1502  /*****   - A 16-bit value that isn't part of the Unicode Surrogates  *****/
1503  /*****     Area (i.e. U+D800-U+DFFF).                                *****/
1504  /*****                                                               *****/
1505  /*****   - A 32-bit value, made of two surrogate values, i.e.. if    *****/
1506  /*****     `char_code = (char_hi << 16) | char_lo', then both        *****/
1507  /*****     `char_hi' and `char_lo' must be in the Surrogates Area.   *****/
1508  /*****      Area.                                                    *****/
1509  /*****                                                               *****/
1510  /***** The 'is32' table embedded in the charmap indicates whether a  *****/
1511  /***** given 16-bit value is in the surrogates area or not.          *****/
1512  /*****                                                               *****/
1513  /***** So, for any given `char_code', we can assert the following:   *****/
1514  /*****                                                               *****/
1515  /*****   If `char_hi == 0' then we must have `is32[char_lo] == 0'.   *****/
1516  /*****                                                               *****/
1517  /*****   If `char_hi != 0' then we must have both                    *****/
1518  /*****   `is32[char_hi] != 0' and `is32[char_lo] != 0'.              *****/
1519  /*****                                                               *****/
1520  /*************************************************************************/
1521  /*************************************************************************/
1522
1523  /*************************************************************************/
1524  /*                                                                       */
1525  /* TABLE OVERVIEW                                                        */
1526  /* --------------                                                        */
1527  /*                                                                       */
1528  /*   NAME        OFFSET         TYPE        DESCRIPTION                  */
1529  /*                                                                       */
1530  /*   format      0              USHORT      must be 8                    */
1531  /*   reseved     2              USHORT      reserved                     */
1532  /*   length      4              ULONG       length in bytes              */
1533  /*   language    8              ULONG       Mac language code            */
1534  /*   is32        12             BYTE[8192]  32-bitness bitmap            */
1535  /*   count       8204           ULONG       number of groups             */
1536  /*                                                                       */
1537  /* This header is followed by 'count' groups of the following format:    */
1538  /*                                                                       */
1539  /*   start       0              ULONG       first charcode               */
1540  /*   end         4              ULONG       last charcode                */
1541  /*   startId     8              ULONG       start glyph id for the group */
1542  /*                                                                       */
1543
1544#ifdef TT_CONFIG_CMAP_FORMAT_8
1545
1546  FT_CALLBACK_DEF( FT_Error )
1547  tt_cmap8_validate( FT_Byte*      table,
1548                     FT_Validator  valid )
1549  {
1550    FT_Byte*   p = table + 4;
1551    FT_Byte*   is32;
1552    FT_UInt32  length;
1553    FT_UInt32  num_groups;
1554
1555
1556    if ( table + 16 + 8192 > valid->limit )
1557      FT_INVALID_TOO_SHORT;
1558
1559    length = TT_NEXT_ULONG( p );
1560    if ( table + length > valid->limit || length < 8208 )
1561      FT_INVALID_TOO_SHORT;
1562
1563    is32       = table + 12;
1564    p          = is32  + 8192;          /* skip `is32' array */
1565    num_groups = TT_NEXT_ULONG( p );
1566
1567    if ( p + num_groups * 12 > valid->limit )
1568      FT_INVALID_TOO_SHORT;
1569
1570    /* check groups, they must be in increasing order */
1571    {
1572      FT_UInt32  n, start, end, start_id, count, last = 0;
1573
1574
1575      for ( n = 0; n < num_groups; n++ )
1576      {
1577        FT_UInt   hi, lo;
1578
1579
1580        start    = TT_NEXT_ULONG( p );
1581        end      = TT_NEXT_ULONG( p );
1582        start_id = TT_NEXT_ULONG( p );
1583
1584        if ( start > end )
1585          FT_INVALID_DATA;
1586
1587        if ( n > 0 && start <= last )
1588          FT_INVALID_DATA;
1589
1590        if ( valid->level >= FT_VALIDATE_TIGHT )
1591        {
1592          if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
1593            FT_INVALID_GLYPH_ID;
1594
1595          count = (FT_UInt32)( end - start + 1 );
1596
1597          if ( start & ~0xFFFFU )
1598          {
1599            /* start_hi != 0; check that is32[i] is 1 for each i in */
1600            /* the `hi' and `lo' of the range [start..end]          */
1601            for ( ; count > 0; count--, start++ )
1602            {
1603              hi = (FT_UInt)( start >> 16 );
1604              lo = (FT_UInt)( start & 0xFFFFU );
1605
1606              if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 )
1607                FT_INVALID_DATA;
1608
1609              if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 )
1610                FT_INVALID_DATA;
1611            }
1612          }
1613          else
1614          {
1615            /* start_hi == 0; check that is32[i] is 0 for each i in */
1616            /* the range [start..end]                               */
1617
1618            /* end_hi cannot be != 0! */
1619            if ( end & ~0xFFFFU )
1620              FT_INVALID_DATA;
1621
1622            for ( ; count > 0; count--, start++ )
1623            {
1624              lo = (FT_UInt)( start & 0xFFFFU );
1625
1626              if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 )
1627                FT_INVALID_DATA;
1628            }
1629          }
1630        }
1631
1632        last = end;
1633      }
1634    }
1635
1636    return SFNT_Err_Ok;
1637  }
1638
1639
1640  FT_CALLBACK_DEF( FT_UInt )
1641  tt_cmap8_char_index( TT_CMap    cmap,
1642                       FT_UInt32  char_code )
1643  {
1644    FT_Byte*   table      = cmap->data;
1645    FT_UInt    result     = 0;
1646    FT_Byte*   p          = table + 8204;
1647    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
1648    FT_UInt32  start, end, start_id;
1649
1650
1651    for ( ; num_groups > 0; num_groups-- )
1652    {
1653      start    = TT_NEXT_ULONG( p );
1654      end      = TT_NEXT_ULONG( p );
1655      start_id = TT_NEXT_ULONG( p );
1656
1657      if ( char_code < start )
1658        break;
1659
1660      if ( char_code <= end )
1661      {
1662        result = (FT_UInt)( start_id + char_code - start );
1663        break;
1664      }
1665    }
1666    return result;
1667  }
1668
1669
1670  FT_CALLBACK_DEF( FT_UInt )
1671  tt_cmap8_char_next( TT_CMap     cmap,
1672                      FT_UInt32  *pchar_code )
1673  {
1674    FT_UInt32  result     = 0;
1675    FT_UInt32  char_code  = *pchar_code + 1;
1676    FT_UInt    gindex     = 0;
1677    FT_Byte*   table      = cmap->data;
1678    FT_Byte*   p          = table + 8204;
1679    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
1680    FT_UInt32  start, end, start_id;
1681
1682
1683    p = table + 8208;
1684
1685    for ( ; num_groups > 0; num_groups-- )
1686    {
1687      start    = TT_NEXT_ULONG( p );
1688      end      = TT_NEXT_ULONG( p );
1689      start_id = TT_NEXT_ULONG( p );
1690
1691      if ( char_code < start )
1692        char_code = start;
1693
1694      if ( char_code <= end )
1695      {
1696        gindex = (FT_UInt)( char_code - start + start_id );
1697        if ( gindex != 0 )
1698        {
1699          result = char_code;
1700          goto Exit;
1701        }
1702      }
1703    }
1704
1705  Exit:
1706    *pchar_code = result;
1707    return gindex;
1708  }
1709
1710
1711  FT_CALLBACK_DEF( FT_Error )
1712  tt_cmap8_get_info( TT_CMap       cmap,
1713                     TT_CMapInfo  *cmap_info )
1714  {
1715    FT_Byte*  p = cmap->data + 8;
1716
1717
1718    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
1719
1720    return SFNT_Err_Ok;
1721  }
1722
1723
1724  FT_CALLBACK_TABLE_DEF
1725  const TT_CMap_ClassRec  tt_cmap8_class_rec =
1726  {
1727    {
1728      sizeof ( TT_CMapRec ),
1729
1730      (FT_CMap_InitFunc)     tt_cmap_init,
1731      (FT_CMap_DoneFunc)     NULL,
1732      (FT_CMap_CharIndexFunc)tt_cmap8_char_index,
1733      (FT_CMap_CharNextFunc) tt_cmap8_char_next
1734    },
1735    8,
1736    (TT_CMap_ValidateFunc)   tt_cmap8_validate,
1737    (TT_CMap_Info_GetFunc)   tt_cmap8_get_info
1738  };
1739
1740#endif /* TT_CONFIG_CMAP_FORMAT_8 */
1741
1742
1743  /*************************************************************************/
1744  /*************************************************************************/
1745  /*****                                                               *****/
1746  /*****                          FORMAT 10                            *****/
1747  /*****                                                               *****/
1748  /*************************************************************************/
1749  /*************************************************************************/
1750
1751  /*************************************************************************/
1752  /*                                                                       */
1753  /* TABLE OVERVIEW                                                        */
1754  /* --------------                                                        */
1755  /*                                                                       */
1756  /*   NAME      OFFSET  TYPE               DESCRIPTION                    */
1757  /*                                                                       */
1758  /*   format     0      USHORT             must be 10                     */
1759  /*   reserved   2      USHORT             reserved                       */
1760  /*   length     4      ULONG              length in bytes                */
1761  /*   language   8      ULONG              Mac language code              */
1762  /*                                                                       */
1763  /*   start     12      ULONG              first char in range            */
1764  /*   count     16      ULONG              number of chars in range       */
1765  /*   glyphIds  20      USHORT[count]      glyph indices covered          */
1766  /*                                                                       */
1767
1768#ifdef TT_CONFIG_CMAP_FORMAT_10
1769
1770  FT_CALLBACK_DEF( FT_Error )
1771  tt_cmap10_validate( FT_Byte*      table,
1772                      FT_Validator  valid )
1773  {
1774    FT_Byte*  p = table + 4;
1775    FT_ULong  length, count;
1776
1777
1778    if ( table + 20 > valid->limit )
1779      FT_INVALID_TOO_SHORT;
1780
1781    length = TT_NEXT_ULONG( p );
1782    p      = table + 16;
1783    count  = TT_NEXT_ULONG( p );
1784
1785    if ( table + length > valid->limit || length < 20 + count * 2 )
1786      FT_INVALID_TOO_SHORT;
1787
1788    /* check glyph indices */
1789    if ( valid->level >= FT_VALIDATE_TIGHT )
1790    {
1791      FT_UInt  gindex;
1792
1793
1794      for ( ; count > 0; count-- )
1795      {
1796        gindex = TT_NEXT_USHORT( p );
1797        if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
1798          FT_INVALID_GLYPH_ID;
1799      }
1800    }
1801
1802    return SFNT_Err_Ok;
1803  }
1804
1805
1806  FT_CALLBACK_DEF( FT_UInt )
1807  tt_cmap10_char_index( TT_CMap    cmap,
1808                        FT_UInt32  char_code )
1809  {
1810    FT_Byte*   table  = cmap->data;
1811    FT_UInt    result = 0;
1812    FT_Byte*   p      = table + 12;
1813    FT_UInt32  start  = TT_NEXT_ULONG( p );
1814    FT_UInt32  count  = TT_NEXT_ULONG( p );
1815    FT_UInt32  idx    = (FT_ULong)( char_code - start );
1816
1817
1818    if ( idx < count )
1819    {
1820      p     += 2 * idx;
1821      result = TT_PEEK_USHORT( p );
1822    }
1823    return result;
1824  }
1825
1826
1827  FT_CALLBACK_DEF( FT_UInt )
1828  tt_cmap10_char_next( TT_CMap     cmap,
1829                       FT_UInt32  *pchar_code )
1830  {
1831    FT_Byte*   table     = cmap->data;
1832    FT_UInt32  char_code = *pchar_code + 1;
1833    FT_UInt    gindex    = 0;
1834    FT_Byte*   p         = table + 12;
1835    FT_UInt32  start     = TT_NEXT_ULONG( p );
1836    FT_UInt32  count     = TT_NEXT_ULONG( p );
1837    FT_UInt32  idx;
1838
1839
1840    if ( char_code < start )
1841      char_code = start;
1842
1843    idx = (FT_UInt32)( char_code - start );
1844    p  += 2 * idx;
1845
1846    for ( ; idx < count; idx++ )
1847    {
1848      gindex = TT_NEXT_USHORT( p );
1849      if ( gindex != 0 )
1850        break;
1851      char_code++;
1852    }
1853
1854    *pchar_code = char_code;
1855    return gindex;
1856  }
1857
1858
1859  FT_CALLBACK_DEF( FT_Error )
1860  tt_cmap10_get_info( TT_CMap       cmap,
1861                      TT_CMapInfo  *cmap_info )
1862  {
1863    FT_Byte*  p = cmap->data + 8;
1864
1865
1866    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
1867
1868    return SFNT_Err_Ok;
1869  }
1870
1871
1872  FT_CALLBACK_TABLE_DEF
1873  const TT_CMap_ClassRec  tt_cmap10_class_rec =
1874  {
1875    {
1876      sizeof ( TT_CMapRec ),
1877
1878      (FT_CMap_InitFunc)     tt_cmap_init,
1879      (FT_CMap_DoneFunc)     NULL,
1880      (FT_CMap_CharIndexFunc)tt_cmap10_char_index,
1881      (FT_CMap_CharNextFunc) tt_cmap10_char_next
1882    },
1883    10,
1884    (TT_CMap_ValidateFunc)   tt_cmap10_validate,
1885    (TT_CMap_Info_GetFunc)   tt_cmap10_get_info
1886  };
1887
1888#endif /* TT_CONFIG_CMAP_FORMAT_10 */
1889
1890
1891  /*************************************************************************/
1892  /*************************************************************************/
1893  /*****                                                               *****/
1894  /*****                          FORMAT 12                            *****/
1895  /*****                                                               *****/
1896  /*************************************************************************/
1897  /*************************************************************************/
1898
1899  /*************************************************************************/
1900  /*                                                                       */
1901  /* TABLE OVERVIEW                                                        */
1902  /* --------------                                                        */
1903  /*                                                                       */
1904  /*   NAME        OFFSET     TYPE       DESCRIPTION                       */
1905  /*                                                                       */
1906  /*   format      0          USHORT     must be 12                        */
1907  /*   reserved    2          USHORT     reserved                          */
1908  /*   length      4          ULONG      length in bytes                   */
1909  /*   language    8          ULONG      Mac language code                 */
1910  /*   count       12         ULONG      number of groups                  */
1911  /*               16                                                      */
1912  /*                                                                       */
1913  /* This header is followed by `count' groups of the following format:    */
1914  /*                                                                       */
1915  /*   start       0          ULONG      first charcode                    */
1916  /*   end         4          ULONG      last charcode                     */
1917  /*   startId     8          ULONG      start glyph id for the group      */
1918  /*                                                                       */
1919
1920#ifdef TT_CONFIG_CMAP_FORMAT_12
1921
1922  typedef struct  TT_CMap12Rec_
1923  {
1924    TT_CMapRec  cmap;
1925    FT_Bool     valid;
1926    FT_ULong    cur_charcode;
1927    FT_UInt     cur_gindex;
1928    FT_ULong    cur_group;
1929    FT_ULong    num_groups;
1930
1931  } TT_CMap12Rec, *TT_CMap12;
1932
1933
1934  FT_CALLBACK_DEF( FT_Error )
1935  tt_cmap12_init( TT_CMap12  cmap,
1936                  FT_Byte*   table )
1937  {
1938    cmap->cmap.data  = table;
1939
1940    table           += 12;
1941    cmap->num_groups = FT_PEEK_ULONG( table );
1942
1943    cmap->valid      = 0;
1944
1945    return SFNT_Err_Ok;
1946  }
1947
1948
1949  FT_CALLBACK_DEF( FT_Error )
1950  tt_cmap12_validate( FT_Byte*      table,
1951                      FT_Validator  valid )
1952  {
1953    FT_Byte*   p;
1954    FT_ULong   length;
1955    FT_ULong   num_groups;
1956
1957
1958    if ( table + 16 > valid->limit )
1959      FT_INVALID_TOO_SHORT;
1960
1961    p      = table + 4;
1962    length = TT_NEXT_ULONG( p );
1963
1964    p          = table + 12;
1965    num_groups = TT_NEXT_ULONG( p );
1966
1967    if ( table + length > valid->limit || length < 16 + 12 * num_groups )
1968      FT_INVALID_TOO_SHORT;
1969
1970    /* check groups, they must be in increasing order */
1971    {
1972      FT_ULong  n, start, end, start_id, last = 0;
1973
1974
1975      for ( n = 0; n < num_groups; n++ )
1976      {
1977        start    = TT_NEXT_ULONG( p );
1978        end      = TT_NEXT_ULONG( p );
1979        start_id = TT_NEXT_ULONG( p );
1980
1981        if ( start > end )
1982          FT_INVALID_DATA;
1983
1984        if ( n > 0 && start <= last )
1985          FT_INVALID_DATA;
1986
1987        if ( valid->level >= FT_VALIDATE_TIGHT )
1988        {
1989          if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
1990            FT_INVALID_GLYPH_ID;
1991        }
1992
1993        last = end;
1994      }
1995    }
1996
1997    return SFNT_Err_Ok;
1998  }
1999
2000
2001  /* search the index of the charcode next to cmap->cur_charcode */
2002  /* cmap->cur_group should be set up properly by caller         */
2003  /*                                                             */
2004  static void
2005  tt_cmap12_next( TT_CMap12  cmap )
2006  {
2007    FT_Byte*  p;
2008    FT_ULong  start, end, start_id, char_code;
2009    FT_ULong  n;
2010    FT_UInt   gindex;
2011
2012
2013    if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
2014      goto Fail;
2015
2016    char_code = cmap->cur_charcode + 1;
2017
2018    n = cmap->cur_group;
2019
2020    for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
2021    {
2022      p        = cmap->cmap.data + 16 + 12 * n;
2023      start    = TT_NEXT_ULONG( p );
2024      end      = TT_NEXT_ULONG( p );
2025      start_id = TT_PEEK_ULONG( p );
2026
2027      if ( char_code < start )
2028        char_code = start;
2029
2030      for ( ; char_code <= end; char_code++ )
2031      {
2032        gindex = (FT_UInt)( start_id + char_code - start );
2033
2034        if ( gindex )
2035        {
2036          cmap->cur_charcode = char_code;;
2037          cmap->cur_gindex   = gindex;
2038          cmap->cur_group    = n;
2039
2040          return;
2041        }
2042      }
2043    }
2044
2045  Fail:
2046    cmap->valid = 0;
2047  }
2048
2049
2050  static FT_UInt
2051  tt_cmap12_char_map_binary( TT_CMap     cmap,
2052                             FT_UInt32*  pchar_code,
2053                             FT_Bool     next )
2054  {
2055    FT_UInt    gindex     = 0;
2056    FT_Byte*   p          = cmap->data + 12;
2057    FT_UInt32  num_groups = TT_PEEK_ULONG( p );
2058    FT_UInt32  char_code  = *pchar_code;
2059    FT_UInt32  start, end, start_id;
2060    FT_UInt32  max, min, mid;
2061
2062
2063    if ( !num_groups )
2064      return 0;
2065
2066    /* make compiler happy */
2067    mid = num_groups;
2068    end = 0xFFFFFFFFUL;
2069
2070    if ( next )
2071      char_code++;
2072
2073    min = 0;
2074    max = num_groups;
2075
2076    /* binary search */
2077    while ( min < max )
2078    {
2079      mid = ( min + max ) >> 1;
2080      p   = cmap->data + 16 + 12 * mid;
2081
2082      start = TT_NEXT_ULONG( p );
2083      end   = TT_NEXT_ULONG( p );
2084
2085      if ( char_code < start )
2086        max = mid;
2087      else if ( char_code > end )
2088        min = mid + 1;
2089      else
2090      {
2091        start_id = TT_PEEK_ULONG( p );
2092        gindex = (FT_UInt)( start_id + char_code - start );
2093
2094        break;
2095      }
2096    }
2097
2098    if ( next )
2099    {
2100      TT_CMap12  cmap12 = (TT_CMap12)cmap;
2101
2102
2103      /* if `char_code' is not in any group, then `mid' is */
2104      /* the group nearest to `char_code'                  */
2105      /*                                                   */
2106
2107      if ( char_code > end )
2108      {
2109        mid++;
2110        if ( mid == num_groups )
2111          return 0;
2112      }
2113
2114      cmap12->valid        = 1;
2115      cmap12->cur_charcode = char_code;
2116      cmap12->cur_group    = mid;
2117
2118      if ( !gindex )
2119      {
2120        tt_cmap12_next( cmap12 );
2121
2122        if ( cmap12->valid )
2123          gindex = cmap12->cur_gindex;
2124      }
2125      else
2126        cmap12->cur_gindex = gindex;
2127
2128      if ( gindex )
2129        *pchar_code = cmap12->cur_charcode;
2130    }
2131
2132    return gindex;
2133  }
2134
2135
2136  FT_CALLBACK_DEF( FT_UInt )
2137  tt_cmap12_char_index( TT_CMap    cmap,
2138                        FT_UInt32  char_code )
2139  {
2140    return tt_cmap12_char_map_binary( cmap, &char_code, 0 );
2141  }
2142
2143
2144  FT_CALLBACK_DEF( FT_UInt )
2145  tt_cmap12_char_next( TT_CMap     cmap,
2146                       FT_UInt32  *pchar_code )
2147  {
2148    TT_CMap12  cmap12 = (TT_CMap12)cmap;
2149    FT_ULong   gindex;
2150
2151
2152    if ( cmap12->cur_charcode >= 0xFFFFFFFFUL )
2153      return 0;
2154
2155    /* no need to search */
2156    if ( cmap12->valid && cmap12->cur_charcode == *pchar_code )
2157    {
2158      tt_cmap12_next( cmap12 );
2159      if ( cmap12->valid )
2160      {
2161        gindex = cmap12->cur_gindex;
2162        if ( gindex )
2163          *pchar_code = cmap12->cur_charcode;
2164      }
2165      else
2166        gindex = 0;
2167    }
2168    else
2169      gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 );
2170
2171    return gindex;
2172  }
2173
2174
2175  FT_CALLBACK_DEF( FT_Error )
2176  tt_cmap12_get_info( TT_CMap       cmap,
2177                      TT_CMapInfo  *cmap_info )
2178  {
2179    FT_Byte*  p = cmap->data + 8;
2180
2181
2182    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
2183
2184    return SFNT_Err_Ok;
2185  }
2186
2187
2188  FT_CALLBACK_TABLE_DEF
2189  const TT_CMap_ClassRec  tt_cmap12_class_rec =
2190  {
2191    {
2192      sizeof ( TT_CMap12Rec ),
2193
2194      (FT_CMap_InitFunc)     tt_cmap12_init,
2195      (FT_CMap_DoneFunc)     NULL,
2196      (FT_CMap_CharIndexFunc)tt_cmap12_char_index,
2197      (FT_CMap_CharNextFunc) tt_cmap12_char_next
2198    },
2199    12,
2200    (TT_CMap_ValidateFunc)   tt_cmap12_validate,
2201    (TT_CMap_Info_GetFunc)   tt_cmap12_get_info
2202  };
2203
2204
2205#endif /* TT_CONFIG_CMAP_FORMAT_12 */
2206
2207
2208  static const TT_CMap_Class  tt_cmap_classes[] =
2209  {
2210#ifdef TT_CONFIG_CMAP_FORMAT_0
2211    &tt_cmap0_class_rec,
2212#endif
2213
2214#ifdef TT_CONFIG_CMAP_FORMAT_2
2215    &tt_cmap2_class_rec,
2216#endif
2217
2218#ifdef TT_CONFIG_CMAP_FORMAT_4
2219    &tt_cmap4_class_rec,
2220#endif
2221
2222#ifdef TT_CONFIG_CMAP_FORMAT_6
2223    &tt_cmap6_class_rec,
2224#endif
2225
2226#ifdef TT_CONFIG_CMAP_FORMAT_8
2227    &tt_cmap8_class_rec,
2228#endif
2229
2230#ifdef TT_CONFIG_CMAP_FORMAT_10
2231    &tt_cmap10_class_rec,
2232#endif
2233
2234#ifdef TT_CONFIG_CMAP_FORMAT_12
2235    &tt_cmap12_class_rec,
2236#endif
2237
2238    NULL,
2239  };
2240
2241
2242  /* parse the `cmap' table and build the corresponding TT_CMap objects */
2243  /* in the current face                                                */
2244  /*                                                                    */
2245  FT_LOCAL_DEF( FT_Error )
2246  tt_face_build_cmaps( TT_Face  face )
2247  {
2248    FT_Byte*           table = face->cmap_table;
2249    FT_Byte*           limit = table + face->cmap_size;
2250    FT_UInt volatile   num_cmaps;
2251    FT_Byte* volatile  p     = table;
2252
2253
2254    if ( p + 4 > limit )
2255      return SFNT_Err_Invalid_Table;
2256
2257    /* only recognize format 0 */
2258    if ( TT_NEXT_USHORT( p ) != 0 )
2259    {
2260      p -= 2;
2261      FT_ERROR(( "tt_face_build_cmaps: unsupported `cmap' table format = %d\n",
2262                 TT_PEEK_USHORT( p ) ));
2263      return SFNT_Err_Invalid_Table;
2264    }
2265
2266    num_cmaps = TT_NEXT_USHORT( p );
2267
2268    for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- )
2269    {
2270      FT_CharMapRec  charmap;
2271      FT_UInt32      offset;
2272
2273
2274      charmap.platform_id = TT_NEXT_USHORT( p );
2275      charmap.encoding_id = TT_NEXT_USHORT( p );
2276      charmap.face        = FT_FACE( face );
2277      charmap.encoding    = FT_ENCODING_NONE;  /* will be filled later */
2278      offset              = TT_NEXT_ULONG( p );
2279
2280      if ( offset && offset <= face->cmap_size - 2 )
2281      {
2282        FT_Byte* volatile              cmap   = table + offset;
2283        volatile FT_UInt               format = TT_PEEK_USHORT( cmap );
2284        const TT_CMap_Class* volatile  pclazz = tt_cmap_classes;
2285        TT_CMap_Class volatile         clazz;
2286
2287
2288        for ( ; *pclazz; pclazz++ )
2289        {
2290          clazz = *pclazz;
2291          if ( clazz->format == format )
2292          {
2293            volatile TT_ValidatorRec  valid;
2294            volatile FT_Error         error = SFNT_Err_Ok;
2295
2296
2297            ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit,
2298                               FT_VALIDATE_DEFAULT );
2299
2300            valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs;
2301
2302            if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer ) == 0 )
2303            {
2304              /* validate this cmap sub-table */
2305              error = clazz->validate( cmap, FT_VALIDATOR( &valid ) );
2306            }
2307
2308            if ( valid.validator.error == 0 )
2309            {
2310              FT_CMap  ttcmap;
2311
2312
2313              if ( !FT_CMap_New( (FT_CMap_Class)clazz,
2314                                 cmap, &charmap, &ttcmap ) )
2315              {
2316                /* it is simpler to directly set `flags' than adding */
2317                /* a parameter to FT_CMap_New                        */
2318                ((TT_CMap)ttcmap)->flags = (FT_Int)error;
2319              }
2320            }
2321            else
2322            {
2323              FT_ERROR(( "tt_face_build_cmaps:" ));
2324              FT_ERROR(( " broken cmap sub-table ignored!\n" ));
2325            }
2326            break;
2327          }
2328        }
2329      }
2330    }
2331
2332    return SFNT_Err_Ok;
2333  }
2334
2335
2336  FT_LOCAL( FT_Error )
2337  tt_get_cmap_info( FT_CharMap    charmap,
2338                    TT_CMapInfo  *cmap_info )
2339  {
2340    FT_CMap        cmap  = (FT_CMap)charmap;
2341    TT_CMap_Class  clazz = (TT_CMap_Class)cmap->clazz;
2342
2343
2344    return clazz->get_cmap_info( charmap, cmap_info );
2345  }
2346
2347
2348/* END */
Note: See TracBrowser for help on using the repository browser.