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