1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  ttcmap.c                                                               */
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*    TrueType character mapping table (cmap) support (body).              */
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
7ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann/*  Copyright 2002-2015 by                                                 */
8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  This file is part of the FreeType project, and may only be used,       */
11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  modified, and distributed under the terms of the FreeType project      */
12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  this file you indicate that you have read the license and              */
14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  understand and accept it fully.                                        */
15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
19e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <ft2build.h>
20e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_DEBUG_H
21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "sferrors.h"           /* must come before FT_INTERNAL_VALIDATE_H */
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
24e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_VALIDATE_H
25e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_STREAM_H
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "ttload.h"
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "ttcmap.h"
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "sfntpic.h"
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* messages during execution.                                            */
36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef  FT_COMPONENT
38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT_COMPONENT  trace_ttcmap
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_PEEK_SHORT   FT_PEEK_SHORT
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_PEEK_USHORT  FT_PEEK_USHORT
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_PEEK_UINT24  FT_PEEK_UOFF3
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_PEEK_LONG    FT_PEEK_LONG
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_PEEK_ULONG   FT_PEEK_ULONG
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_NEXT_SHORT   FT_NEXT_SHORT
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_NEXT_USHORT  FT_NEXT_USHORT
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_NEXT_UINT24  FT_NEXT_UOFF3
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_NEXT_LONG    FT_NEXT_LONG
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TT_NEXT_ULONG   FT_NEXT_ULONG
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
54ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /* Too large glyph index return values are caught in `FT_Get_Char_Index' */
55ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /* and `FT_Get_Next_Char' (the latter calls the internal `next' function */
56ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /* again in this case).  To mark character code return values as invalid */
57ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /* it is sufficient to set the corresponding glyph index return value to */
58ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /* zero.                                                                 */
59ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
60ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap_init( TT_CMap   cmap,
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_Byte*  table )
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->data = table;
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                           FORMAT 0                            *****/
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME        OFFSET         TYPE          DESCRIPTION                */
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format      0              USHORT        must be 0                  */
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length      2              USHORT        table length in bytes      */
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language    4              USHORT        Mac language code          */
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   glyph_ids   6              BYTE[256]     array of glyph indices     */
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*               262                                                     */
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_0
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap0_validate( FT_Byte*      table,
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Validator  valid )
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
98e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  p;
99e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_UInt   length;
100e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
101e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
102e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( table + 2 + 2 > valid->limit )
103e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_INVALID_TOO_SHORT;
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
105e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    p      = table + 2;           /* skip format */
106e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    length = TT_NEXT_USHORT( p );
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + length > valid->limit || length < 262 )
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check glyph indices whenever necessary */
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( valid->level >= FT_VALIDATE_TIGHT )
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  n, idx;
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p = table + 6;
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( n = 0; n < 256; n++ )
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        idx = *p++;
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_GLYPH_ID;
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap0_char_index( TT_CMap    cmap,
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  char_code )
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  table = cmap->data;
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return char_code < 256 ? table[6 + char_code] : 0;
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap0_char_next( TT_CMap     cmap,
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_UInt32  *pchar_code )
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   table    = cmap->data;
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  charcode = *pchar_code;
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  result   = 0;
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex   = 0;
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table += 6;  /* go to glyph IDs */
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( ++charcode < 256 )
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      gindex = table[charcode];
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( gindex != 0 )
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        result = charcode;
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *pchar_code = result;
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap0_get_info( TT_CMap       cmap,
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     TT_CMapInfo  *cmap_info )
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 4;
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 0;
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap0_class_rec,
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMapRec ),
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap_init,
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap0_char_index,
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap0_char_next,
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0,
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap0_validate,
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap0_get_info )
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_0 */
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                          FORMAT 2                             *****/
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** This is used for certain CJK encodings that encode text in a  *****/
209ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /***** mixed 8/16 bits encoding along the following lines.           *****/
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** * Certain byte values correspond to an 8-bit character code   *****/
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   (typically in the range 0..127 for ASCII compatibility).    *****/
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** * Certain byte values signal the first byte of a 2-byte       *****/
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   character code (but these values are also valid as the      *****/
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   second byte of a 2-byte character).                         *****/
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** The following charmap lookup and iteration functions all      *****/
219ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /***** assume that the value `charcode' fulfills the following.      *****/
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
221ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /*****   - For one byte characters, `charcode' is simply the         *****/
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****     character code.                                           *****/
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
224ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /*****   - For two byte characters, `charcode' is the 2-byte         *****/
225ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /*****     character code in big endian format.  More precisely:     *****/
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****       (charcode >> 8)    is the first byte value              *****/
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****       (charcode & 0xFF)  is the second byte value             *****/
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
230ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /***** Note that not all values of `charcode' are valid according    *****/
231ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /***** to these rules, and the function moderately checks the        *****/
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** arguments.                                                    *****/
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME        OFFSET         TYPE            DESCRIPTION              */
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format      0              USHORT          must be 2                */
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length      2              USHORT          table length in bytes    */
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language    4              USHORT          Mac language code        */
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   keys        6              USHORT[256]     sub-header keys          */
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   subs        518            SUBHEAD[NSUBS]  sub-headers array        */
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   glyph_ids   518+NSUB*8     USHORT[]        glyph ID array           */
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* The `keys' table is used to map charcode high-bytes to sub-headers.   */
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* The value of `NSUBS' is the number of sub-headers defined in the      */
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* table and is computed by finding the maximum of the `keys' table.     */
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Note that for any n, `keys[n]' is a byte offset within the `subs'     */
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* table, i.e., it is the corresponding sub-header index multiplied      */
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* by 8.                                                                 */
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
259ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /* Each sub-header has the following format.                             */
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME        OFFSET      TYPE            DESCRIPTION                 */
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   first       0           USHORT          first valid low-byte        */
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   count       2           USHORT          number of valid low-bytes   */
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   delta       4           SHORT           see below                   */
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   offset      6           USHORT          see below                   */
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* A sub-header defines, for each high-byte, the range of valid          */
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* low-bytes within the charmap.  Note that the range defined by `first' */
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* and `count' must be completely included in the interval [0..255]      */
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* according to the specification.                                       */
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* If a character code is contained within a given sub-header, then      */
274ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /* mapping it to a glyph index is done as follows.                       */
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* * The value of `offset' is read.  This is a _byte_ distance from the  */
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   location of the `offset' field itself into a slice of the           */
278ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /*   `glyph_ids' table.  Let's call it `slice' (it is a USHORT[], too).  */
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* * The value `slice[char.lo - first]' is read.  If it is 0, there is   */
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   no glyph for the charcode.  Otherwise, the value of `delta' is      */
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   added to it (modulo 65536) to form a new glyph index.               */
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* It is up to the validation routine to check that all offsets fall     */
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* within the glyph IDs table (and not within the `subs' table itself or */
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* outside of the CMap).                                                 */
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_2
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap2_validate( FT_Byte*      table,
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Validator  valid )
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
295e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  p;
296e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_UInt   length;
297e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   n, max_subs;
299e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  keys;        /* keys table     */
300e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  subs;        /* sub-headers    */
301e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  glyph_ids;   /* glyph ID array */
302e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
304e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( table + 2 + 2 > valid->limit )
305e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_INVALID_TOO_SHORT;
306e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
307e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    p      = table + 2;           /* skip format */
308e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    length = TT_NEXT_USHORT( p );
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + length > valid->limit || length < 6 + 512 )
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    keys = table + 6;
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* parse keys to compute sub-headers count */
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p        = keys;
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    max_subs = 0;
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( n = 0; n < 256; n++ )
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  idx = TT_NEXT_USHORT( p );
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* value must be multiple of 8 */
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 )
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_INVALID_DATA;
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      idx >>= 3;
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( idx > max_subs )
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        max_subs = idx;
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ASSERT( p == table + 518 );
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    subs      = p;
336ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    glyph_ids = subs + ( max_subs + 1 ) * 8;
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( glyph_ids > valid->limit )
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* parse sub-headers */
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( n = 0; n <= max_subs; n++ )
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
343e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_UInt  first_code, code_count, offset;
344e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_Int   delta;
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      first_code = TT_NEXT_USHORT( p );
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      code_count = TT_NEXT_USHORT( p );
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      delta      = TT_NEXT_SHORT( p );
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      offset     = TT_NEXT_USHORT( p );
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* many Dynalab fonts have empty sub-headers */
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( code_count == 0 )
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        continue;
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* check range within 0..255 */
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( valid->level >= FT_VALIDATE_PARANOID )
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( first_code >= 256 || first_code + code_count > 256 )
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* check offset */
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( offset != 0 )
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
366e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov        FT_Byte*  ids;
367e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
368e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ids = p - 2 + offset;
370ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( ids < glyph_ids || ids + code_count * 2 > table + length )
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_OFFSET;
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* check glyph IDs */
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( valid->level >= FT_VALIDATE_TIGHT )
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Byte*  limit = p + code_count * 2;
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt   idx;
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          for ( ; p < limit; )
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            idx = TT_NEXT_USHORT( p );
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( idx != 0 )
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
385ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann              idx = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU;
386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_INVALID_GLYPH_ID;
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* return sub header corresponding to a given character code */
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* NULL on invalid charcode                                  */
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Byte*
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap2_get_subheader( FT_Byte*   table,
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          FT_UInt32  char_code )
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  result = NULL;
405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( char_code < 0x10000UL )
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   char_lo = (FT_UInt)( char_code & 0xFF );
410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   char_hi = (FT_UInt)( char_code >> 8 );
411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  p       = table + 6;    /* keys table */
412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  subs    = table + 518;  /* subheaders table */
413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  sub;
414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_hi == 0 )
417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* an 8-bit character code -- we use subHeader 0 in this case */
419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* to test whether the character code is in the charmap       */
420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /*                                                            */
421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        sub = subs;  /* jump to first sub-header */
422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* check that the sub-header for this byte is 0, which */
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* indicates that it is really a valid one-byte value  */
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* Otherwise, return 0                                 */
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /*                                                     */
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p += char_lo * 2;
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( TT_PEEK_USHORT( p ) != 0 )
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Exit;
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* a 16-bit character code */
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* jump to key entry  */
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p  += char_hi * 2;
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* jump to sub-header */
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) );
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* check that the high byte isn't a valid one-byte value */
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( sub == subs )
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Exit;
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result = sub;
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
446ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap2_char_index( TT_CMap    cmap,
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  char_code )
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  table   = cmap->data;
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   result  = 0;
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  subheader;
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    subheader = tt_cmap2_get_subheader( table, char_code );
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( subheader )
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  p   = subheader;
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   idx = (FT_UInt)(char_code & 0xFF);
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   start, count;
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Int    delta;
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   offset;
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start  = TT_NEXT_USHORT( p );
472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      count  = TT_NEXT_USHORT( p );
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      delta  = TT_NEXT_SHORT ( p );
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      offset = TT_PEEK_USHORT( p );
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      idx -= start;
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( idx < count && offset != 0 )
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p  += offset + 2 * idx;
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        idx = TT_PEEK_USHORT( p );
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( idx != 0 )
483ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          result = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU;
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
486ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap2_char_next( TT_CMap     cmap,
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_UInt32  *pcharcode )
494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   table    = cmap->data;
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex   = 0;
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  result   = 0;
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  charcode = *pcharcode + 1;
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   subheader;
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( charcode < 0x10000UL )
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subheader = tt_cmap2_get_subheader( table, charcode );
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( subheader )
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Byte*  p       = subheader;
508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   start   = TT_NEXT_USHORT( p );
509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   count   = TT_NEXT_USHORT( p );
510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Int    delta   = TT_NEXT_SHORT ( p );
511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   offset  = TT_PEEK_USHORT( p );
512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   char_lo = (FT_UInt)( charcode & 0xFF );
513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   pos, idx;
514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( offset == 0 )
517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Next_SubHeader;
518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( char_lo < start )
520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          char_lo = start;
522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pos     = 0;
523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pos = (FT_UInt)( char_lo - start );
526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p       += offset + pos * 2;
528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo;
529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( ; pos < count; pos++, charcode++ )
531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          idx = TT_NEXT_USHORT( p );
533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( idx != 0 )
535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
536ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            gindex = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU;
537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( gindex != 0 )
538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              result = charcode;
540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Exit;
541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* jump to next sub-header, i.e. higher byte value */
547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    Next_SubHeader:
548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charcode = FT_PAD_FLOOR( charcode, 256 ) + 256;
549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *pcharcode = result;
553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap2_get_info( TT_CMap       cmap,
560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     TT_CMapInfo  *cmap_info )
561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 4;
563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 2;
566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap2_class_rec,
574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMapRec ),
575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap_init,
577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap2_char_index,
579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap2_char_next,
580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap2_validate,
589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap2_get_info )
590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_2 */
592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                           FORMAT 4                            *****/
598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME          OFFSET         TYPE              DESCRIPTION          */
608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format        0              USHORT            must be 4            */
610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length        2              USHORT            table length         */
611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  in bytes             */
612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language      4              USHORT            Mac language code    */
613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   segCountX2    6              USHORT            2*NUM_SEGS           */
615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   searchRange   8              USHORT            2*(1 << LOG_SEGS)    */
616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   entrySelector 10             USHORT            LOG_SEGS             */
617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   rangeShift    12             USHORT            segCountX2 -         */
618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                    searchRange        */
619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   endCount      14             USHORT[NUM_SEGS]  end charcode for     */
621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  each segment; last   */
622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  is 0xFFFF            */
623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   pad           14+NUM_SEGS*2  USHORT            padding              */
625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   startCount    16+NUM_SEGS*2  USHORT[NUM_SEGS]  first charcode for   */
627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  each segment         */
628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   idDelta       16+NUM_SEGS*4  SHORT[NUM_SEGS]   delta for each       */
630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  segment              */
631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   idOffset      16+NUM_SEGS*6  SHORT[NUM_SEGS]   range offset for     */
632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  each segment; can be */
633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  zero                 */
634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   glyphIds      16+NUM_SEGS*8  USHORT[]          array of glyph ID    */
636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                  ranges               */
637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Character codes are modelled by a series of ordered (increasing)      */
639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* intervals called segments.  Each segment has start and end codes,     */
640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* provided by the `startCount' and `endCount' arrays.  Segments must    */
641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* not overlap, and the last segment should always contain the value     */
642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* 0xFFFF for `endCount'.                                                */
643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* The fields `searchRange', `entrySelector' and `rangeShift' are better */
645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* ignored (they are traces of over-engineering in the TrueType          */
646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* specification).                                                       */
647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Each segment also has a signed `delta', as well as an optional offset */
649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* within the `glyphIds' table.                                          */
650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* If a segment's idOffset is 0, the glyph index corresponding to any    */
652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* charcode within the segment is obtained by adding the value of        */
653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* `idDelta' directly to the charcode, modulo 65536.                     */
654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Otherwise, a glyph index is taken from the glyph IDs sub-array for    */
656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* the segment, and the value of `idDelta' is added to it.               */
657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Finally, note that a lot of fonts contain an invalid last segment,    */
660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* where `start' and `end' are correctly set to 0xFFFF but both `delta'  */
661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* and `offset' are incorrect (e.g., `opens___.ttf' which comes with     */
662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* OpenOffice.org).  We need special code to deal with them correctly.   */
663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_4
666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct  TT_CMap4Rec_
668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMapRec  cmap;
670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32   cur_charcode;   /* current charcode */
671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     cur_gindex;     /* current glyph index */
672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     num_ranges;
674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     cur_range;
675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     cur_start;
676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     cur_end;
677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int      cur_delta;
678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*    cur_values;
679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } TT_CMap4Rec, *TT_CMap4;
681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_init( TT_CMap4  cmap,
685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 FT_Byte*  table )
686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p;
688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cmap.data    = table;
691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p                  = table + 6;
693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->num_ranges   = FT_PEEK_USHORT( p ) >> 1;
694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cur_gindex   = 0;
696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Int
702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_set_range( TT_CMap4  cmap,
703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_UInt   range_index )
704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  table = cmap->cmap.data;
706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p;
707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   num_ranges = cmap->num_ranges;
708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( range_index < num_ranges )
711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  offset;
713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p             = table + 14 + range_index * 2;
716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap->cur_end = FT_PEEK_USHORT( p );
717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p              += 2 + num_ranges * 2;
719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap->cur_start = FT_PEEK_USHORT( p );
720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p              += num_ranges * 2;
722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap->cur_delta = FT_PEEK_SHORT( p );
723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p     += num_ranges * 2;
725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      offset = FT_PEEK_USHORT( p );
726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* some fonts have an incorrect last segment; */
728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* we have to catch it                        */
729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( range_index     >= num_ranges - 1 &&
730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           cmap->cur_start == 0xFFFFU        &&
731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           cmap->cur_end   == 0xFFFFU        )
732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TT_Face   face  = (TT_Face)cmap->cmap.cmap.charmap.face;
734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Byte*  limit = face->cmap_table + face->cmap_size;
735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( offset && p + offset + 2 > limit )
738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cmap->cur_delta = 1;
740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          offset          = 0;
741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( offset != 0xFFFFU )
745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmap->cur_values = offset ? p + offset : NULL;
747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmap->cur_range  = range_index;
748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return 0;
749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* we skip empty segments */
752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      range_index++;
753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return -1;
756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* search the index of the charcode next to cmap->cur_charcode; */
760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* caller should call tt_cmap4_set_range with proper range      */
761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* before calling this function                                 */
762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                              */
763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_next( TT_CMap4  cmap )
765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt  charcode;
767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cmap->cur_charcode >= 0xFFFFUL )
770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Fail;
771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    charcode = (FT_UInt)cmap->cur_charcode + 1;
773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( charcode < cmap->cur_start )
775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charcode = cmap->cur_start;
776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ;; )
778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  values = cmap->cur_values;
780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   end    = cmap->cur_end;
781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Int    delta  = cmap->cur_delta;
782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( charcode <= end )
785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( values )
787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Byte*  p = values + 2 * ( charcode - cmap->cur_start );
789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          do
792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_UInt  gindex = FT_NEXT_USHORT( p );
794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( gindex != 0 )
797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
798ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann              gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( gindex != 0 )
800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmap->cur_charcode = charcode;
802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cmap->cur_gindex   = gindex;
803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return;
804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          } while ( ++charcode <= end );
807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          do
811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
812ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            FT_UInt  gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( gindex != 0 )
816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cmap->cur_charcode = charcode;
818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cmap->cur_gindex   = gindex;
819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              return;
820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          } while ( ++charcode <= end );
822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* we need to find another range */
826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 )
827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( charcode < cmap->cur_start )
830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        charcode = cmap->cur_start;
831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Fail:
834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cur_gindex   = 0;
836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_validate( FT_Byte*      table,
841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Validator  valid )
842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
843e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  p;
844e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_UInt   length;
845e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte   *ends, *starts, *offsets, *deltas, *glyph_ids;
847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   num_segs;
848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error  error = FT_Err_Ok;
849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
851e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( table + 2 + 2 > valid->limit )
852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
854e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    p      = table + 2;           /* skip format */
855e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    length = TT_NEXT_USHORT( p );
856e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* in certain fonts, the `length' field is invalid and goes */
858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* out of bound.  We try to correct this here...            */
859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + length > valid->limit )
860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( valid->level >= FT_VALIDATE_TIGHT )
862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_INVALID_TOO_SHORT;
863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      length = (FT_UInt)( valid->limit - table );
865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
867e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( length < 16 )
868e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_INVALID_TOO_SHORT;
869e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p        = table + 6;
871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_segs = TT_NEXT_USHORT( p );   /* read segCountX2 */
872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( valid->level >= FT_VALIDATE_PARANOID )
874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* check that we have an even value here */
876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( num_segs & 1 )
877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_INVALID_DATA;
878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_segs /= 2;
881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( length < 16 + num_segs * 2 * 4 )
883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check the search parameters - even though we never use them */
886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*                                                             */
887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( valid->level >= FT_VALIDATE_PARANOID )
888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* check the values of `searchRange', `entrySelector', `rangeShift' */
890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  search_range   = TT_NEXT_USHORT( p );
891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  entry_selector = TT_NEXT_USHORT( p );
892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  range_shift    = TT_NEXT_USHORT( p );
893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( ( search_range | range_shift ) & 1 )  /* must be even values */
896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_INVALID_DATA;
897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      search_range /= 2;
899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      range_shift  /= 2;
900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* `search range' is the greatest power of 2 that is <= num_segs */
902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( search_range                > num_segs                 ||
904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           search_range * 2            < num_segs                 ||
905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           search_range + range_shift != num_segs                 ||
906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           search_range               != ( 1U << entry_selector ) )
907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_INVALID_DATA;
908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ends      = table   + 14;
911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    starts    = table   + 16 + num_segs * 2;
912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    deltas    = starts  + num_segs * 2;
913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    offsets   = deltas  + num_segs * 2;
914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph_ids = offsets + num_segs * 2;
915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check last segment; its end count value must be 0xFFFF */
917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( valid->level >= FT_VALIDATE_PARANOID )
918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p = ends + ( num_segs - 1 ) * 2;
920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_INVALID_DATA;
922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   start, end, offset, n;
926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt   last_start = 0, last_end = 0;
927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Int    delta;
928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  p_start   = starts;
929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  p_end     = ends;
930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  p_delta   = deltas;
931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  p_offset  = offsets;
932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( n = 0; n < num_segs; n++ )
935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p      = p_offset;
937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        start  = TT_NEXT_USHORT( p_start );
938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        end    = TT_NEXT_USHORT( p_end );
939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        delta  = TT_NEXT_SHORT( p_delta );
940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        offset = TT_NEXT_USHORT( p_offset );
941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( start > end )
943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* this test should be performed at default validation level; */
946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* unfortunately, some popular Asian fonts have overlapping   */
947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* ranges in their charmaps                                   */
948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /*                                                            */
949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( start <= last_end && n > 0 )
950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( valid->level >= FT_VALIDATE_TIGHT )
952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_INVALID_DATA;
953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else
954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* allow overlapping segments, provided their start points */
956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* and end points, respectively, are in ascending order    */
957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /*                                                         */
958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( last_start > start || last_end > end )
959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              error |= TT_CMAP_FLAG_UNSORTED;
960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else
961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              error |= TT_CMAP_FLAG_OVERLAPPING;
962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( offset && offset != 0xFFFFU )
966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p += offset;  /* start of glyph ID array */
968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* check that we point within the glyph IDs table only */
970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( valid->level >= FT_VALIDATE_TIGHT )
971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( p < glyph_ids                                ||
973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 p + ( end - start + 1 ) * 2 > table + length )
974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_DATA;
975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Some fonts handle the last segment incorrectly.  In */
977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* theory, 0xFFFF might point to an ordinary glyph --  */
978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* a cmap 4 is versatile and could be used for any     */
979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* encoding, not only Unicode.  However, reality shows */
980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* that far too many fonts are sloppy and incorrectly  */
981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* set all fields but `start' and `end' for the last   */
982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* segment if it contains only a single character.     */
983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*                                                     */
984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* We thus omit the test here, delaying it to the      */
985ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          /* routines that actually access the cmap.             */
986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else if ( n != num_segs - 1                       ||
987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    !( start == 0xFFFFU && end == 0xFFFFU ) )
988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( p < glyph_ids                              ||
990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 p + ( end - start + 1 ) * 2 > valid->limit )
991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_DATA;
992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* check glyph indices within the segment range */
995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( valid->level >= FT_VALIDATE_TIGHT )
996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_UInt  i, idx;
998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( i = start; i < end; i++ )
1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              idx = FT_NEXT_USHORT( p );
1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( idx != 0 )
1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
1005ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                idx = (FT_UInt)( (FT_Int)idx + delta ) & 0xFFFFU;
1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  FT_INVALID_GLYPH_ID;
1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if ( offset == 0xFFFFU )
1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* some fonts (erroneously?) use a range offset of 0xFFFF */
1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* to mean missing glyph in cmap table                    */
1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*                                                        */
1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( valid->level >= FT_VALIDATE_PARANOID    ||
1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               n != num_segs - 1                       ||
1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               !( start == 0xFFFFU && end == 0xFFFFU ) )
1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_INVALID_DATA;
1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        last_start = start;
1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        last_end   = end;
1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt
1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_char_map_linear( TT_CMap     cmap,
1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            FT_UInt32*  pcharcode,
1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            FT_Bool     next )
1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1038ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
1039ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Byte*  limit = face->cmap_table + face->cmap_size;
1040ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1041ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    num_segs2, start, end, offset;
1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int     delta;
1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    i, num_segs;
1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  charcode = *pcharcode;
1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex   = 0;
1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p;
1048ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Byte*   q;
1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p = cmap->data + 6;
1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_segs = num_segs2 >> 1;
1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !num_segs )
1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( next )
1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charcode++;
1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1062ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if ( charcode > 0xFFFFU )
1063ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      return 0;
1064ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* linear search */
1066ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    p = cmap->data + 14;               /* ends table   */
1067ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    q = cmap->data + 16 + num_segs2;   /* starts table */
1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1069ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    for ( i = 0; i < num_segs; i++ )
1070ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    {
1071ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      end   = TT_NEXT_USHORT( p );
1072ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      start = TT_NEXT_USHORT( q );
1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1074ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( charcode < start )
1075ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      {
1076ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( next )
1077ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          charcode = start;
1078ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        else
1079ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          break;
1080ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      }
1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1082ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    Again:
1083ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( charcode <= end )
1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1085ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        FT_Byte*  r;
1086ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1088ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        r       = q - 2 + num_segs2;
1089ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        delta   = TT_PEEK_SHORT( r );
1090ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        r      += num_segs2;
1091ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        offset  = TT_PEEK_USHORT( r );
1092ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1093ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* some fonts have an incorrect last segment; */
1094ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* we have to catch it                        */
1095ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( i >= num_segs - 1                  &&
1096ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann             start == 0xFFFFU && end == 0xFFFFU )
1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1098ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( offset && r + offset + 2 > limit )
1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1100ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            delta  = 1;
1101ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            offset = 0;
1102ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          }
1103ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        }
1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1105ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( offset == 0xFFFFU )
1106ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          continue;
1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1108ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( offset )
1109ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        {
1110ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          r += offset + ( charcode - start ) * 2;
1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1112ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          /* if r > limit, the whole segment is invalid */
1113ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( next && r > limit )
1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            continue;
1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1116ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          gindex = TT_PEEK_USHORT( r );
1117ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( gindex )
1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1119ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
1120ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            if ( gindex >= (FT_UInt)face->root.num_glyphs )
1121ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann              gindex = 0;
1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1123ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        }
1124ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        else
1125ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        {
1126ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1128ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( next && gindex >= (FT_UInt)face->root.num_glyphs )
1129ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          {
1130ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            /* we have an invalid glyph index; if there is an overflow, */
1131ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            /* we can adjust `charcode', otherwise the whole segment is */
1132ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            /* invalid                                                  */
1133ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            gindex = 0;
1134ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1135ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            if ( (FT_Int)charcode + delta < 0 &&
1136ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                 (FT_Int)end + delta >= 0     )
1137ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann              charcode = (FT_UInt)( -delta );
1138ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1139ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            else if ( (FT_Int)charcode + delta < 0x10000L &&
1140ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                      (FT_Int)end + delta >= 0x10000L     )
1141ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann              charcode = (FT_UInt)( 0x10000L - delta );
1142ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1143ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            else
1144ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann              continue;
1145ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          }
1146ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        }
1147ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1148ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( next && !gindex )
1149ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        {
1150ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( charcode >= 0xFFFFU )
1151ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            break;
1152ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1153ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          charcode++;
1154ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          goto Again;
1155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
1158ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      }
1159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1161ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if ( next )
1162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      *pcharcode = charcode;
1163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
1165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt
1169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_char_map_binary( TT_CMap     cmap,
1170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            FT_UInt32*  pcharcode,
1171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            FT_Bool     next )
1172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   num_segs2, start, end, offset;
1174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int    delta;
1175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   max, min, mid, num_segs;
1176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   charcode = (FT_UInt)*pcharcode;
1177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   gindex   = 0;
1178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p;
1179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p = cmap->data + 6;
1182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
1183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !num_segs2 )
1185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
1186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_segs = num_segs2 >> 1;
1188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* make compiler happy */
1190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    mid = num_segs;
1191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    end = 0xFFFFU;
1192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( next )
1194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charcode++;
1195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    min = 0;
1197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    max = num_segs;
1198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* binary search */
1200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( min < max )
1201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      mid    = ( min + max ) >> 1;
1203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p      = cmap->data + 14 + mid * 2;
1204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      end    = TT_PEEK_USHORT( p );
1205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p     += 2 + num_segs2;
1206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start  = TT_PEEK_USHORT( p );
1207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( charcode < start )
1209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        max = mid;
1210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( charcode > end )
1211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        min = mid + 1;
1212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
1213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p     += num_segs2;
1215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        delta  = TT_PEEK_SHORT( p );
1216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p     += num_segs2;
1217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        offset = TT_PEEK_USHORT( p );
1218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* some fonts have an incorrect last segment; */
1220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* we have to catch it                        */
1221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( mid >= num_segs - 1                &&
1222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov             start == 0xFFFFU && end == 0xFFFFU )
1223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          TT_Face   face  = (TT_Face)cmap->cmap.charmap.face;
1225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Byte*  limit = face->cmap_table + face->cmap_size;
1226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( offset && p + offset + 2 > limit )
1229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            delta  = 1;
1231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            offset = 0;
1232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* search the first segment containing `charcode' */
1236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( cmap->flags & TT_CMAP_FLAG_OVERLAPPING )
1237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UInt  i;
1239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* call the current segment `max' */
1242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          max = mid;
1243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( offset == 0xFFFFU )
1245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            mid = max + 1;
1246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* search in segments before the current segment */
1248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          for ( i = max ; i > 0; i-- )
1249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_UInt   prev_end;
1251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Byte*  old_p;
1252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            old_p    = p;
1255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p        = cmap->data + 14 + ( i - 1 ) * 2;
1256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            prev_end = TT_PEEK_USHORT( p );
1257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( charcode > prev_end )
1259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p = old_p;
1261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            end    = prev_end;
1265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p     += 2 + num_segs2;
1266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            start  = TT_PEEK_USHORT( p );
1267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p     += num_segs2;
1268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            delta  = TT_PEEK_SHORT( p );
1269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p     += num_segs2;
1270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            offset = TT_PEEK_USHORT( p );
1271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( offset != 0xFFFFU )
1273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              mid = i - 1;
1274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* no luck */
1277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( mid == max + 1 )
1278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( i != max )
1280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p      = cmap->data + 14 + max * 2;
1282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              end    = TT_PEEK_USHORT( p );
1283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p     += 2 + num_segs2;
1284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              start  = TT_PEEK_USHORT( p );
1285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p     += num_segs2;
1286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              delta  = TT_PEEK_SHORT( p );
1287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p     += num_segs2;
1288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              offset = TT_PEEK_USHORT( p );
1289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            mid = max;
1292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* search in segments after the current segment */
1294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( i = max + 1; i < num_segs; i++ )
1295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_UInt  next_end, next_start;
1297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p          = cmap->data + 14 + i * 2;
1300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              next_end   = TT_PEEK_USHORT( p );
1301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p         += 2 + num_segs2;
1302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              next_start = TT_PEEK_USHORT( p );
1303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( charcode < next_start )
1305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
1306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              end    = next_end;
1308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              start  = next_start;
1309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p     += num_segs2;
1310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              delta  = TT_PEEK_SHORT( p );
1311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              p     += num_segs2;
1312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              offset = TT_PEEK_USHORT( p );
1313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( offset != 0xFFFFU )
1315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                mid = i;
1316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            i--;
1318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* still no luck */
1320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( mid == max )
1321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              mid = i;
1323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* end, start, delta, and offset are for the i'th segment */
1329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( mid != i )
1330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p      = cmap->data + 14 + mid * 2;
1332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            end    = TT_PEEK_USHORT( p );
1333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p     += 2 + num_segs2;
1334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            start  = TT_PEEK_USHORT( p );
1335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p     += num_segs2;
1336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            delta  = TT_PEEK_SHORT( p );
1337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            p     += num_segs2;
1338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            offset = TT_PEEK_USHORT( p );
1339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
1342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( offset == 0xFFFFU )
1344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
1345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( offset )
1348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p += offset + ( charcode - start ) * 2;
1350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          gindex = TT_PEEK_USHORT( p );
1351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( gindex != 0 )
1352ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            gindex = (FT_UInt)( (FT_Int)gindex + delta ) & 0xFFFFU;
1353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
1355ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          gindex = (FT_UInt)( (FT_Int)charcode + delta ) & 0xFFFFU;
1356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
1358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( next )
1362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      TT_CMap4  cmap4 = (TT_CMap4)cmap;
1364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* if `charcode' is not in any segment, then `mid' is */
1367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* the segment nearest to `charcode'                  */
1368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( charcode > end )
1370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mid++;
1372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( mid == num_segs )
1373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return 0;
1374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( tt_cmap4_set_range( cmap4, mid ) )
1377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( gindex )
1379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          *pcharcode = charcode;
1380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
1382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmap4->cur_charcode = charcode;
1384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( gindex )
1386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cmap4->cur_gindex = gindex;
1387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
1388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cmap4->cur_charcode = charcode;
1390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          tt_cmap4_next( cmap4 );
1391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          gindex = cmap4->cur_gindex;
1392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( gindex )
1395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          *pcharcode = cmap4->cur_charcode;
1396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
1400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
1404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_char_index( TT_CMap    cmap,
1405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  char_code )
1406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( char_code >= 0x10000UL )
1408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
1409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
1411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return tt_cmap4_char_map_linear( cmap, &char_code, 0 );
1412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
1413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return tt_cmap4_char_map_binary( cmap, &char_code, 0 );
1414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
1418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_char_next( TT_CMap     cmap,
1419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_UInt32  *pchar_code )
1420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt  gindex;
1422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( *pchar_code >= 0xFFFFU )
1425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
1426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
1428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 );
1429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
1430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      TT_CMap4  cmap4 = (TT_CMap4)cmap;
1432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* no need to search */
1435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( *pchar_code == cmap4->cur_charcode )
1436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        tt_cmap4_next( cmap4 );
1438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = cmap4->cur_gindex;
1439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( gindex )
1440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          *pchar_code = cmap4->cur_charcode;
1441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
1443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 );
1444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
1447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
1451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap4_get_info( TT_CMap       cmap,
1452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     TT_CMapInfo  *cmap_info )
1453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 4;
1455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 4;
1458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
1459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
1461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
1465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap4_class_rec,
1466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMap4Rec ),
1467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap4_init,
1468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
1469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
1470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap4_char_next,
1471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    4,
1479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap4_validate,
1480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap4_get_info )
1481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_4 */
1483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                          FORMAT 6                             *****/
1489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
1496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
1497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME        OFFSET          TYPE             DESCRIPTION            */
1499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1500ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /*   format       0              USHORT           must be 6              */
1501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length       2              USHORT           table length in bytes  */
1502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language     4              USHORT           Mac language code      */
1503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   first        6              USHORT           first segment code     */
1505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   count        8              USHORT           segment size in chars  */
1506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   glyphIds     10             USHORT[count]    glyph IDs              */
1507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* A very simplified segment mapping.                                    */
1509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_6
1512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
1514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap6_validate( FT_Byte*      table,
1515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Validator  valid )
1516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p;
1518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   length, count;
1519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + 10 > valid->limit )
1522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
1523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p      = table + 2;
1525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    length = TT_NEXT_USHORT( p );
1526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p      = table + 8;             /* skip language and start index */
1528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    count  = TT_NEXT_USHORT( p );
1529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1530e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( table + length > valid->limit || length < 10 + count * 2 )
1531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
1532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check glyph indices */
1534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( valid->level >= FT_VALIDATE_TIGHT )
1535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  gindex;
1537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ; count > 0; count-- )
1540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = TT_NEXT_USHORT( p );
1542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
1543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_GLYPH_ID;
1544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
1548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
1552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap6_char_index( TT_CMap    cmap,
1553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  char_code )
1554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  table  = cmap->data;
1556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   result = 0;
1557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p      = table + 6;
1558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   start  = TT_NEXT_USHORT( p );
1559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   count  = TT_NEXT_USHORT( p );
1560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   idx    = (FT_UInt)( char_code - start );
1561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( idx < count )
1564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p += 2 * idx;
1566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result = TT_PEEK_USHORT( p );
1567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1568ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
1570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
1574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap6_char_next( TT_CMap     cmap,
1575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_UInt32  *pchar_code )
1576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   table     = cmap->data;
1578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  result    = 0;
1579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  char_code = *pchar_code + 1;
1580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex    = 0;
1581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p         = table + 6;
1583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    start     = TT_NEXT_USHORT( p );
1584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    count     = TT_NEXT_USHORT( p );
1585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    idx;
1586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( char_code >= 0x10000UL )
1589ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      return 0;
1590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( char_code < start )
1592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      char_code = start;
1593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    idx = (FT_UInt)( char_code - start );
1595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p  += 2 * idx;
1596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ; idx < count; idx++ )
1598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      gindex = TT_NEXT_USHORT( p );
1600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( gindex != 0 )
1601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        result = char_code;
1603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
1604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1605ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1606ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( char_code >= 0xFFFFU )
1607ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return 0;
1608ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      char_code++;
1610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *pchar_code = result;
1613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
1614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
1618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap6_get_info( TT_CMap       cmap,
1619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     TT_CMapInfo  *cmap_info )
1620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 4;
1622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 6;
1625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p );
1626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
1628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
1632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap6_class_rec,
1633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMapRec ),
1634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap_init,
1636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
1637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap6_char_index,
1638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap6_char_next,
1639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    6,
1647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap6_validate,
1648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap6_get_info )
1649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_6 */
1651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                          FORMAT 8                             *****/
1657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** It is hard to completely understand what the OpenType spec    *****/
1659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** says about this format, but here is my conclusion.            *****/
1660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** The purpose of this format is to easily map UTF-16 text to    *****/
1662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** glyph indices.  Basically, the `char_code' must be in one of  *****/
1663ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /***** the following formats.                                        *****/
1664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   - A 16-bit value that isn't part of the Unicode Surrogates  *****/
1666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****     Area (i.e. U+D800-U+DFFF).                                *****/
1667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   - A 32-bit value, made of two surrogate values, i.e.. if    *****/
1669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****     `char_code = (char_hi << 16) | char_lo', then both        *****/
1670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****     `char_hi' and `char_lo' must be in the Surrogates Area.   *****/
1671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****      Area.                                                    *****/
1672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** The `is32' table embedded in the charmap indicates whether a  *****/
1674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /***** given 16-bit value is in the surrogates area or not.          *****/
1675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1676ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  /***** So, for any given `char_code', we can assert the following.   *****/
1677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   If `char_hi == 0' then we must have `is32[char_lo] == 0'.   *****/
1679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   If `char_hi != 0' then we must have both                    *****/
1681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****   `is32[char_hi] != 0' and `is32[char_lo] != 0'.              *****/
1682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
1689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
1690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME        OFFSET         TYPE        DESCRIPTION                  */
1692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format      0              USHORT      must be 8                    */
1694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   reserved    2              USHORT      reserved                     */
1695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length      4              ULONG       length in bytes              */
1696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language    8              ULONG       Mac language code            */
1697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   is32        12             BYTE[8192]  32-bitness bitmap            */
1698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   count       8204           ULONG       number of groups             */
1699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* This header is followed by `count' groups of the following format:    */
1701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   start       0              ULONG       first charcode               */
1703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   end         4              ULONG       last charcode                */
1704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   startId     8              ULONG       start glyph ID for the group */
1705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_8
1708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
1710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap8_validate( FT_Byte*      table,
1711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Validator  valid )
1712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p = table + 4;
1714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   is32;
1715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  length;
1716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  num_groups;
1717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + 16 + 8192 > valid->limit )
1720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
1721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    length = TT_NEXT_ULONG( p );
1723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( length > (FT_UInt32)( valid->limit - table ) || length < 8192 + 16 )
1724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
1725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    is32       = table + 12;
1727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p          = is32  + 8192;          /* skip `is32' array */
1728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_groups = TT_NEXT_ULONG( p );
1729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1730e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    /* p + num_groups * 12 > valid->limit ? */
1731e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( num_groups > (FT_UInt32)( valid->limit - p ) / 12 )
1732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
1733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check groups, they must be in increasing order */
1735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  n, start, end, start_id, count, last = 0;
1737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( n = 0; n < num_groups; n++ )
1740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_UInt   hi, lo;
1742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        start    = TT_NEXT_ULONG( p );
1745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        end      = TT_NEXT_ULONG( p );
1746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        start_id = TT_NEXT_ULONG( p );
1747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( start > end )
1749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
1750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( n > 0 && start <= last )
1752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
1753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( valid->level >= FT_VALIDATE_TIGHT )
1755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1756e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          FT_UInt32  d = end - start;
1757e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1758e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
1759e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          /* start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ? */
1760e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          if ( d > TT_VALID_GLYPH_COUNT( valid )             ||
1761e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov               start_id >= TT_VALID_GLYPH_COUNT( valid ) - d )
1762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_INVALID_GLYPH_ID;
1763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          count = (FT_UInt32)( end - start + 1 );
1765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( start & ~0xFFFFU )
1767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* start_hi != 0; check that is32[i] is 1 for each i in */
1769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* the `hi' and `lo' of the range [start..end]          */
1770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( ; count > 0; count--, start++ )
1771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              hi = (FT_UInt)( start >> 16 );
1773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              lo = (FT_UInt)( start & 0xFFFFU );
1774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 )
1776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_INVALID_DATA;
1777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 )
1779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_INVALID_DATA;
1780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else
1783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* start_hi == 0; check that is32[i] is 0 for each i in */
1785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* the range [start..end]                               */
1786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* end_hi cannot be != 0! */
1788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( end & ~0xFFFFU )
1789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_DATA;
1790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( ; count > 0; count--, start++ )
1792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              lo = (FT_UInt)( start & 0xFFFFU );
1794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 )
1796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_INVALID_DATA;
1797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        last = end;
1802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
1806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
1810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap8_char_index( TT_CMap    cmap,
1811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  char_code )
1812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   table      = cmap->data;
1814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    result     = 0;
1815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p          = table + 8204;
1816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
1817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  start, end, start_id;
1818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ; num_groups > 0; num_groups-- )
1821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start    = TT_NEXT_ULONG( p );
1823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      end      = TT_NEXT_ULONG( p );
1824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start_id = TT_NEXT_ULONG( p );
1825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < start )
1827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
1828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code <= end )
1830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1831ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
1832ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          return 0;
1833ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1834ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        result = (FT_UInt)( start_id + ( char_code - start ) );
1835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
1836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
1839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
1843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap8_char_next( TT_CMap     cmap,
1844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_UInt32  *pchar_code )
1845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1846ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Face    face       = cmap->cmap.charmap.face;
1847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  result     = 0;
1848ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_UInt32  char_code;
1849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex     = 0;
1850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   table      = cmap->data;
1851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p          = table + 8204;
1852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
1853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  start, end, start_id;
1854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1856ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if ( *pchar_code >= 0xFFFFFFFFUL )
1857ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      return 0;
1858ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1859ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    char_code = *pchar_code + 1;
1860ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p = table + 8208;
1862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ; num_groups > 0; num_groups-- )
1864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start    = TT_NEXT_ULONG( p );
1866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      end      = TT_NEXT_ULONG( p );
1867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start_id = TT_NEXT_ULONG( p );
1868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < start )
1870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        char_code = start;
1871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1872ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    Again:
1873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code <= end )
1874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1875ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* ignore invalid group */
1876ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
1877ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          continue;
1878ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1879ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        gindex = (FT_UInt)( start_id + ( char_code - start ) );
1880ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1881ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* does first element of group point to `.notdef' glyph? */
1882ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( gindex == 0 )
1883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1884ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( char_code >= 0xFFFFFFFFUL )
1885ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            break;
1886ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1887ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          char_code++;
1888ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          goto Again;
1889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1890ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1891ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* if `gindex' is invalid, the remaining values */
1892ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* in this group are invalid, too               */
1893ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( gindex >= (FT_UInt)face->num_glyphs )
1894ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          continue;
1895ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
1896ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        result = char_code;
1897ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        break;
1898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
1900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *pchar_code = result;
1902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
1903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
1907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap8_get_info( TT_CMap       cmap,
1908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     TT_CMapInfo  *cmap_info )
1909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 8;
1911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 8;
1914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
1915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
1917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
1918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
1921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap8_class_rec,
1922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMapRec ),
1923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap_init,
1925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
1926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap8_char_index,
1927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap8_char_next,
1928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
1934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    8,
1936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap8_validate,
1937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap8_get_info )
1938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_8 */
1940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                          FORMAT 10                            *****/
1946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
1947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
1951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
1953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
1954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME      OFFSET  TYPE               DESCRIPTION                    */
1956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format     0      USHORT             must be 10                     */
1958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   reserved   2      USHORT             reserved                       */
1959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length     4      ULONG              length in bytes                */
1960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language   8      ULONG              Mac language code              */
1961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   start     12      ULONG              first char in range            */
1963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   count     16      ULONG              number of chars in range       */
1964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   glyphIds  20      USHORT[count]      glyph indices covered          */
1965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
1966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_10
1968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
1970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap10_validate( FT_Byte*      table,
1971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Validator  valid )
1972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
1973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = table + 4;
1974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  length, count;
1975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + 20 > valid->limit )
1978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
1979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    length = TT_NEXT_ULONG( p );
1981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p      = table + 16;
1982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    count  = TT_NEXT_ULONG( p );
1983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( length > (FT_ULong)( valid->limit - table ) ||
1985e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         /* length < 20 + count * 2 ? */
1986e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         length < 20                                 ||
1987e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         ( length - 20 ) / 2 < count                 )
1988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
1989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check glyph indices */
1991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( valid->level >= FT_VALIDATE_TIGHT )
1992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
1993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt  gindex;
1994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ; count > 0; count-- )
1997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = TT_NEXT_USHORT( p );
1999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
2000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_GLYPH_ID;
2001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
2009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap10_char_index( TT_CMap    cmap,
2010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_UInt32  char_code )
2011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   table  = cmap->data;
2013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    result = 0;
2014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p      = table + 12;
2015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  start  = TT_NEXT_ULONG( p );
2016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  count  = TT_NEXT_ULONG( p );
2017ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_UInt32  idx;
2018ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2019ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2020ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if ( char_code < start )
2021ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      return 0;
2022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2023ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    idx = char_code - start;
2024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( idx < count )
2026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p     += 2 * idx;
2028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result = TT_PEEK_USHORT( p );
2029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2030ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
2032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
2036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap10_char_next( TT_CMap     cmap,
2037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  *pchar_code )
2038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   table     = cmap->data;
2040ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_UInt32  char_code;
2041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex    = 0;
2042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p         = table + 12;
2043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  start     = TT_NEXT_ULONG( p );
2044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  count     = TT_NEXT_ULONG( p );
2045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  idx;
2046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2048ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if ( *pchar_code >= 0xFFFFFFFFUL )
2049ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      return 0;
2050ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2051ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    char_code = *pchar_code + 1;
2052ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( char_code < start )
2054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      char_code = start;
2055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2056ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    idx = char_code - start;
2057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p  += 2 * idx;
2058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ; idx < count; idx++ )
2060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      gindex = TT_NEXT_USHORT( p );
2062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( gindex != 0 )
2063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
2064ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2065ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( char_code >= 0xFFFFFFFFUL )
2066ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return 0;
2067ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      char_code++;
2069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *pchar_code = char_code;
2072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
2073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap10_get_info( TT_CMap       cmap,
2078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      TT_CMapInfo  *cmap_info )
2079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 8;
2081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 10;
2084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
2085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
2091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap10_class_rec,
2092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMapRec ),
2093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap_init,
2095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
2096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap10_char_index,
2097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap10_char_next,
2098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    10,
2106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap10_validate,
2107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap10_get_info )
2108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_10 */
2110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
2115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                          FORMAT 12                            *****/
2116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
2117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
2123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
2124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME        OFFSET     TYPE       DESCRIPTION                       */
2126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format      0          USHORT     must be 12                        */
2128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   reserved    2          USHORT     reserved                          */
2129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length      4          ULONG      length in bytes                   */
2130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language    8          ULONG      Mac language code                 */
2131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   count       12         ULONG      number of groups                  */
2132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*               16                                                      */
2133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* This header is followed by `count' groups of the following format:    */
2135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   start       0          ULONG      first charcode                    */
2137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   end         4          ULONG      last charcode                     */
2138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   startId     8          ULONG      start glyph ID for the group      */
2139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_12
2142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct  TT_CMap12Rec_
2144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMapRec  cmap;
2146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Bool     valid;
2147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    cur_charcode;
2148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     cur_gindex;
2149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    cur_group;
2150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    num_groups;
2151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } TT_CMap12Rec, *TT_CMap12;
2153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap12_init( TT_CMap12  cmap,
2157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  FT_Byte*   table )
2158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cmap.data  = table;
2160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table           += 12;
2162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->num_groups = FT_PEEK_ULONG( table );
2163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->valid      = 0;
2165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap12_validate( FT_Byte*      table,
2172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Validator  valid )
2173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2174e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  p;
2175e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_ULong  length;
2176e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_ULong  num_groups;
2177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + 16 > valid->limit )
2180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
2181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p      = table + 4;
2183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    length = TT_NEXT_ULONG( p );
2184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p          = table + 12;
2186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_groups = TT_NEXT_ULONG( p );
2187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( length > (FT_ULong)( valid->limit - table ) ||
2189e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         /* length < 16 + 12 * num_groups ? */
2190e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         length < 16                                 ||
2191e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         ( length - 16 ) / 12 < num_groups           )
2192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
2193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check groups, they must be in increasing order */
2195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong  n, start, end, start_id, last = 0;
2197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( n = 0; n < num_groups; n++ )
2200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        start    = TT_NEXT_ULONG( p );
2202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        end      = TT_NEXT_ULONG( p );
2203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        start_id = TT_NEXT_ULONG( p );
2204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( start > end )
2206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
2207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( n > 0 && start <= last )
2209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
2210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( valid->level >= FT_VALIDATE_TIGHT )
2212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2213e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          FT_UInt32  d = end - start;
2214e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
2215e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
2216e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          /* start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ? */
2217e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          if ( d > TT_VALID_GLYPH_COUNT( valid )             ||
2218e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov               start_id >= TT_VALID_GLYPH_COUNT( valid ) - d )
2219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_INVALID_GLYPH_ID;
2220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        last = end;
2223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* search the index of the charcode next to cmap->cur_charcode */
2231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* cmap->cur_group should be set up properly by caller         */
2232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                             */
2233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
2234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap12_next( TT_CMap12  cmap )
2235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2236ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Face   face = cmap->cmap.cmap.charmap.face;
2237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p;
2238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  start, end, start_id, char_code;
2239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  n;
2240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   gindex;
2241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
2244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Fail;
2245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char_code = cmap->cur_charcode + 1;
2247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
2249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p        = cmap->cmap.data + 16 + 12 * n;
2251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start    = TT_NEXT_ULONG( p );
2252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      end      = TT_NEXT_ULONG( p );
2253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start_id = TT_PEEK_ULONG( p );
2254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < start )
2256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        char_code = start;
2257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2258ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    Again:
2259ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( char_code <= end )
2260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2261ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* ignore invalid group */
2262ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
2263ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          continue;
2264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2265ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        gindex = (FT_UInt)( start_id + ( char_code - start ) );
2266ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2267ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* does first element of group point to `.notdef' glyph? */
2268ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( gindex == 0 )
2269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2270ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          if ( char_code >= 0xFFFFFFFFUL )
2271ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            goto Fail;
2272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2273ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          char_code++;
2274ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          goto Again;
2275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2276ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2277ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* if `gindex' is invalid, the remaining values */
2278ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* in this group are invalid, too               */
2279ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( gindex >= (FT_UInt)face->num_glyphs )
2280ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          continue;
2281ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2282ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        cmap->cur_charcode = char_code;
2283ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        cmap->cur_gindex   = gindex;
2284ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        cmap->cur_group    = n;
2285ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2286ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return;
2287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Fail:
2291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->valid = 0;
2292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt
2296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap12_char_map_binary( TT_CMap     cmap,
2297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             FT_UInt32*  pchar_code,
2298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             FT_Bool     next )
2299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex     = 0;
2301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p          = cmap->data + 12;
2302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  num_groups = TT_PEEK_ULONG( p );
2303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  char_code  = *pchar_code;
2304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  start, end, start_id;
2305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  max, min, mid;
2306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !num_groups )
2309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
2310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* make compiler happy */
2312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    mid = num_groups;
2313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    end = 0xFFFFFFFFUL;
2314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( next )
2316ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    {
2317ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( char_code >= 0xFFFFFFFFUL )
2318ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return 0;
2319ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      char_code++;
2321ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    }
2322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    min = 0;
2324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    max = num_groups;
2325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* binary search */
2327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( min < max )
2328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      mid = ( min + max ) >> 1;
2330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p   = cmap->data + 16 + 12 * mid;
2331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start = TT_NEXT_ULONG( p );
2333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      end   = TT_NEXT_ULONG( p );
2334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < start )
2336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        max = mid;
2337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( char_code > end )
2338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        min = mid + 1;
2339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        start_id = TT_PEEK_ULONG( p );
2342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2343ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        /* reject invalid glyph index */
2344ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( start_id > 0xFFFFFFFFUL - ( char_code - start ) )
2345ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          gindex = 0;
2346ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        else
2347ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          gindex = (FT_UInt)( start_id + ( char_code - start ) );
2348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
2349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( next )
2353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2354ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      FT_Face    face   = cmap->cmap.charmap.face;
2355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      TT_CMap12  cmap12 = (TT_CMap12)cmap;
2356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* if `char_code' is not in any group, then `mid' is */
2359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* the group nearest to `char_code'                  */
2360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code > end )
2362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mid++;
2364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( mid == num_groups )
2365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return 0;
2366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap12->valid        = 1;
2369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap12->cur_charcode = char_code;
2370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap12->cur_group    = mid;
2371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2372ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( gindex >= (FT_UInt)face->num_glyphs )
2373ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        gindex = 0;
2374ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( !gindex )
2376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        tt_cmap12_next( cmap12 );
2378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( cmap12->valid )
2380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          gindex = cmap12->cur_gindex;
2381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmap12->cur_gindex = gindex;
2384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2385ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      *pchar_code = cmap12->cur_charcode;
2386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
2389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
2393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap12_char_index( TT_CMap    cmap,
2394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_UInt32  char_code )
2395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return tt_cmap12_char_map_binary( cmap, &char_code, 0 );
2397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
2401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap12_char_next( TT_CMap     cmap,
2402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  *pchar_code )
2403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap12  cmap12 = (TT_CMap12)cmap;
2405ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_UInt    gindex;
2406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* no need to search */
2409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cmap12->valid && cmap12->cur_charcode == *pchar_code )
2410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      tt_cmap12_next( cmap12 );
2412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( cmap12->valid )
2413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2414ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        gindex      = cmap12->cur_gindex;
2415ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        *pchar_code = (FT_UInt32)cmap12->cur_charcode;
2416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = 0;
2419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
2421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 );
2422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2423ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    return gindex;
2424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap12_get_info( TT_CMap       cmap,
2429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      TT_CMapInfo  *cmap_info )
2430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 8;
2432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 12;
2435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
2436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
2442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap12_class_rec,
2443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMap12Rec ),
2444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap12_init,
2446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
2447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap12_char_index,
2448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap12_char_next,
2449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    12,
2457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap12_validate,
2458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap12_get_info )
2459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_12 */
2461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
2466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                          FORMAT 13                            *****/
2467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
2468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
2474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
2475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME        OFFSET     TYPE       DESCRIPTION                       */
2477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format      0          USHORT     must be 13                        */
2479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   reserved    2          USHORT     reserved                          */
2480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length      4          ULONG      length in bytes                   */
2481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   language    8          ULONG      Mac language code                 */
2482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   count       12         ULONG      number of groups                  */
2483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*               16                                                      */
2484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* This header is followed by `count' groups of the following format:    */
2486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   start       0          ULONG      first charcode                    */
2488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   end         4          ULONG      last charcode                     */
2489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   glyphId     8          ULONG      glyph ID for the whole group      */
2490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_13
2493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct  TT_CMap13Rec_
2495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMapRec  cmap;
2497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Bool     valid;
2498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    cur_charcode;
2499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     cur_gindex;
2500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    cur_group;
2501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    num_groups;
2502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } TT_CMap13Rec, *TT_CMap13;
2504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap13_init( TT_CMap13  cmap,
2508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  FT_Byte*   table )
2509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cmap.data  = table;
2511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table           += 12;
2513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->num_groups = FT_PEEK_ULONG( table );
2514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->valid      = 0;
2516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap13_validate( FT_Byte*      table,
2523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Validator  valid )
2524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p;
2526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  length;
2527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  num_groups;
2528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table + 16 > valid->limit )
2531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
2532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p      = table + 4;
2534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    length = TT_NEXT_ULONG( p );
2535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p          = table + 12;
2537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_groups = TT_NEXT_ULONG( p );
2538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( length > (FT_ULong)( valid->limit - table ) ||
2540e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         /* length < 16 + 12 * num_groups ? */
2541e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         length < 16                                 ||
2542e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         ( length - 16 ) / 12 < num_groups           )
2543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
2544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check groups, they must be in increasing order */
2546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong  n, start, end, glyph_id, last = 0;
2548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( n = 0; n < num_groups; n++ )
2551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        start    = TT_NEXT_ULONG( p );
2553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        end      = TT_NEXT_ULONG( p );
2554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph_id = TT_NEXT_ULONG( p );
2555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( start > end )
2557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
2558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( n > 0 && start <= last )
2560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
2561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( valid->level >= FT_VALIDATE_TIGHT )
2563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( glyph_id >= TT_VALID_GLYPH_COUNT( valid ) )
2565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_INVALID_GLYPH_ID;
2566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        last = end;
2569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* search the index of the charcode next to cmap->cur_charcode */
2577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* cmap->cur_group should be set up properly by caller         */
2578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                             */
2579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
2580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap13_next( TT_CMap13  cmap )
2581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2582ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Face   face = cmap->cmap.cmap.charmap.face;
2583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p;
2584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  start, end, glyph_id, char_code;
2585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  n;
2586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt   gindex;
2587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
2590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Fail;
2591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    char_code = cmap->cur_charcode + 1;
2593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
2595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p        = cmap->cmap.data + 16 + 12 * n;
2597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start    = TT_NEXT_ULONG( p );
2598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      end      = TT_NEXT_ULONG( p );
2599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      glyph_id = TT_PEEK_ULONG( p );
2600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < start )
2602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        char_code = start;
2603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code <= end )
2605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = (FT_UInt)glyph_id;
2607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2608ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        if ( gindex && gindex < (FT_UInt)face->num_glyphs )
2609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2610ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          cmap->cur_charcode = char_code;
2611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cmap->cur_gindex   = gindex;
2612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cmap->cur_group    = n;
2613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return;
2615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Fail:
2620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->valid = 0;
2621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt
2625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap13_char_map_binary( TT_CMap     cmap,
2626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             FT_UInt32*  pchar_code,
2627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             FT_Bool     next )
2628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex     = 0;
2630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*   p          = cmap->data + 12;
2631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  num_groups = TT_PEEK_ULONG( p );
2632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  char_code  = *pchar_code;
2633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  start, end;
2634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  max, min, mid;
2635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !num_groups )
2638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
2639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* make compiler happy */
2641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    mid = num_groups;
2642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    end = 0xFFFFFFFFUL;
2643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( next )
2645ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    {
2646ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( char_code >= 0xFFFFFFFFUL )
2647ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        return 0;
2648ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      char_code++;
2650ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    }
2651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    min = 0;
2653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    max = num_groups;
2654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* binary search */
2656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( min < max )
2657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      mid = ( min + max ) >> 1;
2659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p   = cmap->data + 16 + 12 * mid;
2660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      start = TT_NEXT_ULONG( p );
2662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      end   = TT_NEXT_ULONG( p );
2663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < start )
2665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        max = mid;
2666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( char_code > end )
2667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        min = mid + 1;
2668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = (FT_UInt)TT_PEEK_ULONG( p );
2671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
2673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( next )
2677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2678ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      FT_Face    face   = cmap->cmap.charmap.face;
2679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      TT_CMap13  cmap13 = (TT_CMap13)cmap;
2680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* if `char_code' is not in any group, then `mid' is */
2683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* the group nearest to `char_code'                  */
2684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code > end )
2686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        mid++;
2688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( mid == num_groups )
2689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return 0;
2690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap13->valid        = 1;
2693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap13->cur_charcode = char_code;
2694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cmap13->cur_group    = mid;
2695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2696ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( gindex >= (FT_UInt)face->num_glyphs )
2697ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        gindex = 0;
2698ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann
2699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( !gindex )
2700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        tt_cmap13_next( cmap13 );
2702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( cmap13->valid )
2704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          gindex = cmap13->cur_gindex;
2705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cmap13->cur_gindex = gindex;
2708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2709ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      *pchar_code = cmap13->cur_charcode;
2710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
2713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
2717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap13_char_index( TT_CMap    cmap,
2718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_UInt32  char_code )
2719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return tt_cmap13_char_map_binary( cmap, &char_code, 0 );
2721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
2725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap13_char_next( TT_CMap     cmap,
2726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  *pchar_code )
2727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap13  cmap13 = (TT_CMap13)cmap;
2729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    gindex;
2730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* no need to search */
2733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cmap13->valid && cmap13->cur_charcode == *pchar_code )
2734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      tt_cmap13_next( cmap13 );
2736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( cmap13->valid )
2737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2738ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        gindex      = cmap13->cur_gindex;
2739ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        *pchar_code = cmap13->cur_charcode;
2740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        gindex = 0;
2743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
2745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 );
2746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return gindex;
2748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap13_get_info( TT_CMap       cmap,
2753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      TT_CMapInfo  *cmap_info )
2754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = cmap->data + 8;
2756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 13;
2759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p );
2760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
2766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap13_class_rec,
2767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMap13Rec ),
2768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap13_init,
2770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     NULL,
2771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap13_char_index,
2772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap13_char_next,
2773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
2779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    13,
2781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap13_validate,
2782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap13_get_info )
2783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_13 */
2785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
2790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                           FORMAT 14                           *****/
2791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*****                                                               *****/
2792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* TABLE OVERVIEW                                                        */
2798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* --------------                                                        */
2799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   NAME         OFFSET  TYPE    DESCRIPTION                            */
2801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   format         0     USHORT  must be 14                             */
2803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   length         2     ULONG   table length in bytes                  */
2804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   numSelector    6     ULONG   number of variation sel. records       */
2805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Followed by numSelector records, each of which looks like             */
2807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   varSelector    0     UINT24  Unicode codepoint of sel.              */
2809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   defaultOff     3     ULONG   offset to a default UVS table          */
2810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                describing any variants to be found in */
2811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                the normal Unicode subtable.           */
2812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   nonDefOff      7     ULONG   offset to a non-default UVS table      */
2813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                describing any variants not in the     */
2814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                standard cmap, with GIDs here          */
2815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* (either offset may be 0 NULL)                                         */
2816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Selectors are sorted by code point.                                   */
2818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* A default Unicode Variation Selector (UVS) subtable is just a list of */
2820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* ranges of code points which are to be found in the standard cmap.  No */
2821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* glyph IDs (GIDs) here.                                                */
2822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   numRanges      0     ULONG   number of ranges following             */
2824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* A range looks like                                                    */
2826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   uniStart       0     UINT24  code point of the first character in   */
2828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                this range                             */
2829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   additionalCnt  3     UBYTE   count of additional characters in this */
2830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                range (zero means a range of a single  */
2831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                character)                             */
2832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Ranges are sorted by `uniStart'.                                      */
2834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* A non-default Unicode Variation Selector (UVS) subtable is a list of  */
2836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* mappings from codepoint to GID.                                       */
2837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   numMappings    0     ULONG   number of mappings                     */
2839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* A range looks like                                                    */
2841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   uniStart       0     UINT24  code point of the first character in   */
2843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                this range                             */
2844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*   GID            3     USHORT  and its GID                            */
2845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
2846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* Ranges are sorted by `uniStart'.                                      */
2847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_CMAP_FORMAT_14
2849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct  TT_CMap14Rec_
2851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMapRec  cmap;
2853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    num_selectors;
2854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* This array is used to store the results of various
2856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     * cmap 14 query functions.  The data is overwritten
2857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     * on each call to these functions.
2858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov     */
2859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32   max_results;
2860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32*  results;
2861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory   memory;
2862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } TT_CMap14Rec, *TT_CMap14;
2864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( void )
2867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_done( TT_CMap14  cmap )
2868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory  memory = cmap->memory;
2870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->max_results = 0;
2873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( memory != NULL && cmap->results != NULL )
2874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_FREE( cmap->results );
2875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Error
2879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_ensure( TT_CMap14  cmap,
2880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_UInt32  num_results,
2881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_Memory  memory )
2882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  old_max = cmap->max_results;
2884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error   error   = FT_Err_Ok;
2885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( num_results > cmap->max_results )
2888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       cmap->memory = memory;
2890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       if ( FT_QRENEW_ARRAY( cmap->results, old_max, num_results ) )
2892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         return error;
2893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       cmap->max_results = num_results;
2895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
2898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_init( TT_CMap14  cmap,
2903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  FT_Byte*   table )
2904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->cmap.data = table;
2906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table               += 6;
2908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->num_selectors  = FT_PEEK_ULONG( table );
2909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->max_results    = 0;
2910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap->results        = NULL;
2911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
2917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_validate( FT_Byte*      table,
2918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Validator  valid )
2919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2920e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_Byte*  p;
2921e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_ULong  length;
2922e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    FT_ULong  num_selectors;
2923e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
2924e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
2925e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( table + 2 + 4 + 4 > valid->limit )
2926e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_INVALID_TOO_SHORT;
2927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2928e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    p             = table + 2;
2929e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    length        = TT_NEXT_ULONG( p );
2930e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    num_selectors = TT_NEXT_ULONG( p );
2931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( length > (FT_ULong)( valid->limit - table ) ||
2933e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         /* length < 10 + 11 * num_selectors ? */
2934e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         length < 10                                 ||
2935e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov         ( length - 10 ) / 11 < num_selectors        )
2936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_INVALID_TOO_SHORT;
2937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check selectors, they must be in increasing order */
2939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* we start lastVarSel at 1 because a variant selector value of 0
2941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       * isn't valid.
2942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov       */
2943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong  n, lastVarSel = 1;
2944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( n = 0; n < num_selectors; n++ )
2947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_ULong  varSel    = TT_NEXT_UINT24( p );
2949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_ULong  defOff    = TT_NEXT_ULONG( p );
2950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_ULong  nondefOff = TT_NEXT_ULONG( p );
2951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( defOff >= length || nondefOff >= length )
2954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_TOO_SHORT;
2955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( varSel < lastVarSel )
2957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_INVALID_DATA;
2958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        lastVarSel = varSel + 1;
2960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* check the default table (these glyphs should be reached     */
2962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* through the normal Unicode cmap, no GIDs, just check order) */
2963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( defOff != 0 )
2964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Byte*  defp      = table + defOff;
2966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ULong  numRanges = TT_NEXT_ULONG( defp );
2967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ULong  i;
2968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ULong  lastBase  = 0;
2969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2971e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          /* defp + numRanges * 4 > valid->limit ? */
2972e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          if ( numRanges > (FT_ULong)( valid->limit - defp ) / 4 )
2973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_INVALID_TOO_SHORT;
2974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          for ( i = 0; i < numRanges; ++i )
2976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_ULong  base = TT_NEXT_UINT24( defp );
2978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_ULong  cnt  = FT_NEXT_BYTE( defp );
2979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( base + cnt >= 0x110000UL )              /* end of Unicode */
2982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_DATA;
2983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( base < lastBase )
2985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_DATA;
2986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            lastBase = base + cnt + 1U;
2988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* and the non-default table (these glyphs are specified here) */
2992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( nondefOff != 0 )
2993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Byte*  ndp         = table + nondefOff;
2995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ULong  numMappings = TT_NEXT_ULONG( ndp );
2996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ULong  i, lastUni  = 0;
2997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2999e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          /* numMappings * 4 > (FT_ULong)( valid->limit - ndp ) ? */
3000e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov          if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 4 )
3001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_INVALID_TOO_SHORT;
3002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          for ( i = 0; i < numMappings; ++i )
3004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
3005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_ULong  uni = TT_NEXT_UINT24( ndp );
3006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_ULong  gid = TT_NEXT_USHORT( ndp );
3007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( uni >= 0x110000UL )                     /* end of Unicode */
3010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_DATA;
3011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( uni < lastUni )
3013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_DATA;
3014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            lastUni = uni + 1U;
3016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( valid->level >= FT_VALIDATE_TIGHT    &&
3018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 gid >= TT_VALID_GLYPH_COUNT( valid ) )
3019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_INVALID_GLYPH_ID;
3020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
3021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
3023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
3026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
3030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_char_index( TT_CMap    cmap,
3031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_UInt32  char_code )
3032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( cmap );
3034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( char_code );
3035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* This can't happen */
3037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
3038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 )
3042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_char_next( TT_CMap     cmap,
3043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt32  *pchar_code )
3044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( cmap );
3046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* This can't happen */
3048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *pchar_code = 0;
3049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
3050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Error )
3054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_get_info( TT_CMap       cmap,
3055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      TT_CMapInfo  *cmap_info )
3056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( cmap );
3058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->format   = 14;
3060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* subtable 14 does not define a language field */
3061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cmap_info->language = 0xFFFFFFFFUL;
3062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
3064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt
3068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_char_map_def_binary( FT_Byte    *base,
3069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                 FT_UInt32   char_code )
3070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  numRanges = TT_PEEK_ULONG( base );
3072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  max, min;
3073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    min = 0;
3076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    max = numRanges;
3077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    base += 4;
3079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* binary search */
3081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( min < max )
3082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  mid   = ( min + max ) >> 1;
3084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*   p     = base + 4 * mid;
3085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong   start = TT_NEXT_UINT24( p );
3086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt    cnt   = FT_NEXT_BYTE( p );
3087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < start )
3090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        max = mid;
3091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( char_code > start+cnt )
3092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        min = mid + 1;
3093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
3094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return TRUE;
3095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FALSE;
3098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt
3102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_char_map_nondef_binary( FT_Byte    *base,
3103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                    FT_UInt32   char_code )
3104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  numMappings = TT_PEEK_ULONG( base );
3106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  max, min;
3107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    min = 0;
3110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    max = numMappings;
3111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    base += 4;
3113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* binary search */
3115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( min < max )
3116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  mid = ( min + max ) >> 1;
3118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*   p   = base + 5 * mid;
3119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  uni = (FT_UInt32)TT_NEXT_UINT24( p );
3120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( char_code < uni )
3123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        max = mid;
3124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( char_code > uni )
3125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        min = mid + 1;
3126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
3127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return TT_PEEK_USHORT( p );
3128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
3131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Byte*
3135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_find_variant( FT_Byte    *base,
3136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          FT_UInt32   variantCode )
3137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  numVar = TT_PEEK_ULONG( base );
3139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  max, min;
3140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    min = 0;
3143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    max = numVar;
3144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    base += 4;
3146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* binary search */
3148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( min < max )
3149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  mid    = ( min + max ) >> 1;
3151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*   p      = base + 11 * mid;
3152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong   varSel = TT_NEXT_UINT24( p );
3153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( variantCode < varSel )
3156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        max = mid;
3157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( variantCode > varSel )
3158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        min = mid + 1;
3159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
3160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return p;
3161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return NULL;
3164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt )
3168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_char_var_index( TT_CMap    cmap,
3169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            TT_CMap    ucmap,
3170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            FT_UInt32  charcode,
3171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            FT_UInt32  variantSelector )
3172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
3174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  defOff;
3175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  nondefOff;
3176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !p )
3179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
3180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    defOff    = TT_NEXT_ULONG( p );
3182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nondefOff = TT_PEEK_ULONG( p );
3183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( defOff != 0                                                    &&
3185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
3186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* This is the default variant of this charcode.  GID not stored */
3188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* here; stored in the normal Unicode charmap instead.           */
3189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode );
3190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( nondefOff != 0 )
3193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
3194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               charcode );
3195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
3197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_Int )
3201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_char_var_isdefault( TT_CMap    cmap,
3202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                FT_UInt32  charcode,
3203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                FT_UInt32  variantSelector )
3204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*  p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
3206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  defOff;
3207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong  nondefOff;
3208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !p )
3211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return -1;
3212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    defOff    = TT_NEXT_ULONG( p );
3214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nondefOff = TT_NEXT_ULONG( p );
3215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( defOff != 0                                                    &&
3217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
3218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 1;
3219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( nondefOff != 0                                            &&
3221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
3222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                           charcode ) != 0         )
3223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
3224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return -1;
3226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32* )
3230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_variants( TT_CMap    cmap,
3231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Memory  memory )
3232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap14   cmap14 = (TT_CMap14)cmap;
3234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32   count  = cmap14->num_selectors;
3235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*    p      = cmap->data + 10;
3236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32*  result;
3237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32   i;
3238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) )
3241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
3242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    result = cmap14->results;
3244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( i = 0; i < count; ++i )
3245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result[i] = (FT_UInt32)TT_NEXT_UINT24( p );
3247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p        += 8;
3248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    result[i] = 0;
3250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
3252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 * )
3256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_char_variants( TT_CMap    cmap,
3257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_Memory  memory,
3258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_UInt32  charCode )
3259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap14   cmap14 = (TT_CMap14)  cmap;
3261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32   count  = cmap14->num_selectors;
3262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*    p      = cmap->data + 10;
3263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32*  q;
3264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) )
3267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
3268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( q = cmap14->results; count > 0; --count )
3270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  varSel    = TT_NEXT_UINT24( p );
3272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong   defOff    = TT_NEXT_ULONG( p );
3273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong   nondefOff = TT_NEXT_ULONG( p );
3274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( ( defOff != 0                                               &&
3277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov             tt_cmap14_char_map_def_binary( cmap->data + defOff,
3278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                            charCode )                 ) ||
3279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           ( nondefOff != 0                                            &&
3280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov             tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
3281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               charCode ) != 0         ) )
3282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
3283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        q[0] = varSel;
3284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        q++;
3285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
3286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    q[0] = 0;
3288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmap14->results;
3290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt
3294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_def_char_count( FT_Byte  *p )
3295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  numRanges = (FT_UInt32)TT_NEXT_ULONG( p );
3297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    tot       = 0;
3298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    p += 3;  /* point to the first `cnt' field */
3301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ; numRanges > 0; numRanges-- )
3302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      tot += 1 + p[0];
3304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p   += 4;
3305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return tot;
3308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt32*
3312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_get_def_chars( TT_CMap    cmap,
3313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_Byte*   p,
3314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_Memory  memory )
3315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap14   cmap14 = (TT_CMap14) cmap;
3317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32   numRanges;
3318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     cnt;
3319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32*  q;
3320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cnt       = tt_cmap14_def_char_count( p );
3323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    numRanges = (FT_UInt32)TT_NEXT_ULONG( p );
3324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( tt_cmap14_ensure( cmap14, ( cnt + 1 ), memory ) )
3326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
3327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( q = cmap14->results; numRanges > 0; --numRanges )
3329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  uni = (FT_UInt32)TT_NEXT_UINT24( p );
3331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cnt = FT_NEXT_BYTE( p ) + 1;
3334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      do
3335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
3336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        q[0]  = uni;
3337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        uni  += 1;
3338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        q    += 1;
3339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      } while ( --cnt != 0 );
3341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    q[0] = 0;
3343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return cmap14->results;
3345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_UInt32*
3349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_get_nondef_chars( TT_CMap     cmap,
3350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              FT_Byte    *p,
3351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              FT_Memory   memory )
3352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap14   cmap14 = (TT_CMap14) cmap;
3354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32   numMappings;
3355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt     i;
3356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32  *ret;
3357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    numMappings = (FT_UInt32)TT_NEXT_ULONG( p );
3360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( tt_cmap14_ensure( cmap14, ( numMappings + 1 ), memory ) )
3362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
3363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ret = cmap14->results;
3365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( i = 0; i < numMappings; ++i )
3366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ret[i] = (FT_UInt32)TT_NEXT_UINT24( p );
3368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p += 2;
3369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ret[i] = 0;
3371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return ret;
3373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_CALLBACK_DEF( FT_UInt32 * )
3377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_cmap14_variant_chars( TT_CMap    cmap,
3378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_Memory  memory,
3379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_UInt32  variantSelector )
3380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte    *p  = tt_cmap14_find_variant( cmap->data + 6,
3382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             variantSelector );
3383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int      i;
3384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    defOff;
3385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong    nondefOff;
3386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !p )
3389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
3390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    defOff    = TT_NEXT_ULONG( p );
3392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    nondefOff = TT_NEXT_ULONG( p );
3393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( defOff == 0 && nondefOff == 0 )
3395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
3396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( defOff == 0 )
3398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
3399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                         memory );
3400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else if ( nondefOff == 0 )
3401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
3402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                      memory );
3403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
3404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* Both a default and a non-default glyph set?  That's probably not */
3406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* good font design, but the spec allows for it...                  */
3407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      TT_CMap14  cmap14 = (TT_CMap14) cmap;
3408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  numRanges;
3409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  numMappings;
3410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  duni;
3411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  dcnt;
3412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32  nuni;
3413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*   dp;
3414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt    di, ni, k;
3415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3416e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov      FT_UInt32  *ret;
3417e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
3418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p  = cmap->data + nondefOff;
3420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      dp = cmap->data + defOff;
3421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      numMappings = (FT_UInt32)TT_NEXT_ULONG( p );
3423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      dcnt        = tt_cmap14_def_char_count( dp );
3424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      numRanges   = (FT_UInt32)TT_NEXT_ULONG( dp );
3425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( numMappings == 0 )
3427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
3428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                        memory );
3429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( dcnt == 0 )
3430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
3431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                           memory );
3432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) )
3434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
3435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ret  = cmap14->results;
3437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      duni = (FT_UInt32)TT_NEXT_UINT24( dp );
3438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      dcnt = FT_NEXT_BYTE( dp );
3439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      di   = 1;
3440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      nuni = (FT_UInt32)TT_NEXT_UINT24( p );
3441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      p   += 2;
3442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ni   = 1;
3443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      i    = 0;
3444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ;; )
3446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
3447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( nuni > duni + dcnt )
3448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          for ( k = 0; k <= dcnt; ++k )
3450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ret[i++] = duni + k;
3451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ++di;
3453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( di > numRanges )
3455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
3456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          duni = (FT_UInt32)TT_NEXT_UINT24( dp );
3458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          dcnt = FT_NEXT_BYTE( dp );
3459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
3461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( nuni < duni )
3463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ret[i++] = nuni;
3464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* If it is within the default range then ignore it -- */
3465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* that should not have happened                       */
3466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ++ni;
3467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( ni > numMappings )
3468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
3469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          nuni = (FT_UInt32)TT_NEXT_UINT24( p );
3471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p += 2;
3472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
3474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( ni <= numMappings )
3476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
3477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* If we get here then we have run out of all default ranges.   */
3478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* We have read one non-default mapping which we haven't stored */
3479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* and there may be others that need to be read.                */
3480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ret[i++] = nuni;
3481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        while ( ni < numMappings )
3482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ret[i++] = (FT_UInt32)TT_NEXT_UINT24( p );
3484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          p += 2;
3485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ++ni;
3486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
3488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else if ( di <= numRanges )
3489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
3490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* If we get here then we have run out of all non-default     */
3491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* mappings.  We have read one default range which we haven't */
3492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* stored and there may be others that need to be read.       */
3493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( k = 0; k <= dcnt; ++k )
3494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ret[i++] = duni + k;
3495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        while ( di < numRanges )
3497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          duni = (FT_UInt32)TT_NEXT_UINT24( dp );
3499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          dcnt = FT_NEXT_BYTE( dp );
3500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          for ( k = 0; k <= dcnt; ++k )
3502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ret[i++] = duni + k;
3503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ++di;
3504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
3506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ret[i] = 0;
3508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return ret;
3510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DEFINE_TT_CMAP(
3515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    tt_cmap14_class_rec,
3516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    sizeof ( TT_CMap14Rec ),
3517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_InitFunc)     tt_cmap14_init,
3519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_DoneFunc)     tt_cmap14_done,
3520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharIndexFunc)tt_cmap14_char_index,
3521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharNextFunc) tt_cmap14_char_next,
3522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Format 14 extension functions */
3524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharVarIndexFunc)    tt_cmap14_char_var_index,
3525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault,
3526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_VariantListFunc)     tt_cmap14_variants,
3527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants,
3528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars,
3529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    14,
3531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_ValidateFunc)tt_cmap14_validate,
3532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    (TT_CMap_Info_GetFunc)tt_cmap14_get_info )
3533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_CMAP_FORMAT_14 */
3535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifndef FT_CONFIG_OPTION_PIC
3538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static const TT_CMap_Class  tt_cmap_classes[] =
3540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TTCMAPCITEM( a )  &a,
3542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "ttcmapc.h"
3543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    NULL,
3544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  };
3545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else /*FT_CONFIG_OPTION_PIC*/
3547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  void
3549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_Destroy_Class_tt_cmap_classes( FT_Library      library,
3550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                    TT_CMap_Class*  clazz )
3551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory  memory = library->memory;
3553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( clazz )
3556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_FREE( clazz );
3557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_Error
3561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_Create_Class_tt_cmap_classes( FT_Library       library,
3562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                   TT_CMap_Class**  output_class )
3563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap_Class*     clazz  = NULL;
3565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap_ClassRec*  recs;
3566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error           error;
3567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory          memory = library->memory;
3568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int  i = 0;
3570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define TTCMAPCITEM( a ) i++;
3573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "ttcmapc.h"
3574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* allocate enough space for both the pointers */
3576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* plus terminator and the class instances     */
3577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( FT_ALLOC( clazz, sizeof ( *clazz ) * ( i + 1 ) +
3578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          sizeof ( TT_CMap_ClassRec ) * i ) )
3579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return error;
3580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* the location of the class instances follows the array of pointers */
3582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    recs = (TT_CMap_ClassRec*)( (char*)clazz +
3583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                sizeof ( *clazz ) * ( i + 1 ) );
3584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    i    = 0;
3585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#undef TTCMAPCITEM
3587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define  TTCMAPCITEM( a )             \
3588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Init_Class_ ## a( &recs[i] );  \
3589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    clazz[i] = &recs[i];              \
3590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    i++;
3591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "ttcmapc.h"
3592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    clazz[i] = NULL;
3594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *output_class = clazz;
3596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
3597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /*FT_CONFIG_OPTION_PIC*/
3600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* parse the `cmap' table and build the corresponding TT_CMap objects */
3603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* in the current face                                                */
3604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                    */
3605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
3606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_face_build_cmaps( TT_Face  face )
3607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*           table = face->cmap_table;
3609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*           limit = table + face->cmap_size;
3610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt volatile   num_cmaps;
3611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte* volatile  p     = table;
3612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Library         library = FT_FACE_LIBRARY( face );
3613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( library );
3615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !p || p + 4 > limit )
3618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Invalid_Table );
3619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* only recognize format 0 */
3621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( TT_NEXT_USHORT( p ) != 0 )
3622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ERROR(( "tt_face_build_cmaps:"
3624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 " unsupported `cmap' table format = %d\n",
3625ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                 TT_PEEK_USHORT( p - 2 ) ));
3626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Invalid_Table );
3627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    num_cmaps = TT_NEXT_USHORT( p );
3630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- )
3632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
3633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_CharMapRec  charmap;
3634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_UInt32      offset;
3635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charmap.platform_id = TT_NEXT_USHORT( p );
3638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charmap.encoding_id = TT_NEXT_USHORT( p );
3639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charmap.face        = FT_FACE( face );
3640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      charmap.encoding    = FT_ENCODING_NONE;  /* will be filled later */
3641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      offset              = TT_NEXT_ULONG( p );
3642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( offset && offset <= face->cmap_size - 2 )
3644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
3645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Byte* volatile              cmap   = table + offset;
3646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        volatile FT_UInt               format = TT_PEEK_USHORT( cmap );
3647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        const TT_CMap_Class* volatile  pclazz = TT_CMAP_CLASSES_GET;
3648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TT_CMap_Class volatile         clazz;
3649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( ; *pclazz; pclazz++ )
3652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          clazz = *pclazz;
3654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( clazz->format == format )
3655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
3656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            volatile TT_ValidatorRec  valid;
3657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            volatile FT_Error         error = FT_Err_Ok;
3658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit,
3661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                               FT_VALIDATE_DEFAULT );
3662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs;
3664e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov
3665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer) == 0 )
3666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
3667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* validate this cmap sub-table */
3668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              error = clazz->validate( cmap, FT_VALIDATOR( &valid ) );
3669e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov            }
3670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( valid.validator.error == 0 )
3672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
3673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_CMap  ttcmap;
3674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* It might make sense to store the single variation         */
3677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* selector cmap somewhere special.  But it would have to be */
3678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* in the public FT_FaceRec, and we can't change that.       */
3679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( !FT_CMap_New( (FT_CMap_Class)clazz,
3681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                 cmap, &charmap, &ttcmap ) )
3682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
3683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /* it is simpler to directly set `flags' than adding */
3684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /* a parameter to FT_CMap_New                        */
3685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                ((TT_CMap)ttcmap)->flags = (FT_Int)error;
3686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
3687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
3688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else
3689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
3690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_TRACE0(( "tt_face_build_cmaps:"
3691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          " broken cmap sub-table ignored\n" ));
3692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
3693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
3694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
3695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( *pclazz == NULL )
3698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE0(( "tt_face_build_cmaps:"
3700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      " unsupported cmap sub-table ignored\n" ));
3701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
3703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
3706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL( FT_Error )
3710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  tt_get_cmap_info( FT_CharMap    charmap,
3711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    TT_CMapInfo  *cmap_info )
3712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
3713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_CMap        cmap  = (FT_CMap)charmap;
3714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_CMap_Class  clazz = (TT_CMap_Class)cmap->clazz;
3715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return clazz->get_cmap_info( charmap, cmap_info );
3718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */
3722