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