1/****************************************************************************
2 *
3 * ttpost.c
4 *
5 * PostScript name table processing for TrueType and OpenType fonts
6 * (body).
7 *
8 * Copyright (C) 1996-2019 by
9 * David Turner, Robert Wilhelm, and Werner Lemberg.
10 *
11 * This file is part of the FreeType project, and may only be used,
12 * modified, and distributed under the terms of the FreeType project
13 * license, LICENSE.TXT. By continuing to use, modify, or distribute
14 * this file you indicate that you have read the license and
15 * understand and accept it fully.
16 *
17 */
18
19 /**************************************************************************
20 *
21 * The post table is not completely loaded by the core engine. This
22 * file loads the missing PS glyph names and implements an API to access
23 * them.
24 *
25 */
26
27
28#include <ft2build.h>
29#include FT_INTERNAL_DEBUG_H
30#include FT_INTERNAL_STREAM_H
31#include FT_TRUETYPE_TAGS_H
32
33
34#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
35
36#include "ttpost.h"
37
38#include "sferrors.h"
39
40
41 /**************************************************************************
42 *
43 * The macro FT_COMPONENT is used in trace mode. It is an implicit
44 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
45 * messages during execution.
46 */
47#undef FT_COMPONENT
48#define FT_COMPONENT ttpost
49
50
51 /* If this configuration macro is defined, we rely on the `psnames' */
52 /* module to grab the glyph names. */
53
54#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
55
56
57#include FT_SERVICE_POSTSCRIPT_CMAPS_H
58
59#define MAC_NAME( x ) (FT_String*)psnames->macintosh_name( (FT_UInt)(x) )
60
61
62#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
63
64
65 /* Otherwise, we ignore the `psnames' module, and provide our own */
66 /* table of Mac names. Thus, it is possible to build a version of */
67 /* FreeType without the Type 1 driver & psnames module. */
68
69#define MAC_NAME( x ) (FT_String*)tt_post_default_names[x]
70
71 /* the 258 default Mac PS glyph names; see file `tools/glnames.py' */
72
73 static const FT_String* const tt_post_default_names[258] =
74 {
75 /* 0 */
76 ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
77 "quotedbl", "numbersign", "dollar", "percent", "ampersand",
78 /* 10 */
79 "quotesingle", "parenleft", "parenright", "asterisk", "plus",
80 "comma", "hyphen", "period", "slash", "zero",
81 /* 20 */
82 "one", "two", "three", "four", "five",
83 "six", "seven", "eight", "nine", "colon",
84 /* 30 */
85 "semicolon", "less", "equal", "greater", "question",
86 "at", "A", "B", "C", "D",
87 /* 40 */
88 "E", "F", "G", "H", "I",
89 "J", "K", "L", "M", "N",
90 /* 50 */
91 "O", "P", "Q", "R", "S",
92 "T", "U", "V", "W", "X",
93 /* 60 */
94 "Y", "Z", "bracketleft", "backslash", "bracketright",
95 "asciicircum", "underscore", "grave", "a", "b",
96 /* 70 */
97 "c", "d", "e", "f", "g",
98 "h", "i", "j", "k", "l",
99 /* 80 */
100 "m", "n", "o", "p", "q",
101 "r", "s", "t", "u", "v",
102 /* 90 */
103 "w", "x", "y", "z", "braceleft",
104 "bar", "braceright", "asciitilde", "Adieresis", "Aring",
105 /* 100 */
106 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
107 "aacute", "agrave", "acircumflex", "adieresis", "atilde",
108 /* 110 */
109 "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
110 "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
111 /* 120 */
112 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
113 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
114 /* 130 */
115 "dagger", "degree", "cent", "sterling", "section",
116 "bullet", "paragraph", "germandbls", "registered", "copyright",
117 /* 140 */
118 "trademark", "acute", "dieresis", "notequal", "AE",
119 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
120 /* 150 */
121 "yen", "mu", "partialdiff", "summation", "product",
122 "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
123 /* 160 */
124 "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
125 "radical", "florin", "approxequal", "Delta", "guillemotleft",
126 /* 170 */
127 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
128 "Otilde", "OE", "oe", "endash", "emdash",
129 /* 180 */
130 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
131 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
132 /* 190 */
133 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
134 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
135 /* 200 */
136 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
137 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
138 /* 210 */
139 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
140 "dotlessi", "circumflex", "tilde", "macron", "breve",
141 /* 220 */
142 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
143 "caron", "Lslash", "lslash", "Scaron", "scaron",
144 /* 230 */
145 "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
146 "Yacute", "yacute", "Thorn", "thorn", "minus",
147 /* 240 */
148 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
149 "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
150 /* 250 */
151 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
152 "Ccaron", "ccaron", "dcroat",
153 };
154
155
156#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
157
158
159 static FT_Error
160 load_format_20( TT_Face face,
161 FT_Stream stream,
162 FT_ULong post_limit )
163 {
164 FT_Memory memory = stream->memory;
165 FT_Error error;
166
167 FT_Int num_glyphs;
168 FT_UShort num_names;
169
170 FT_UShort* glyph_indices = NULL;
171 FT_Char** name_strings = NULL;
172
173
174 if ( FT_READ_USHORT( num_glyphs ) )
175 goto Exit;
176
177 /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
178 /* than the value in the maxp table (cf. cyberbit.ttf). */
179
180 /* There already exist fonts which have more than 32768 glyph names */
181 /* in this table, so the test for this threshold has been dropped. */
182
183 if ( num_glyphs > face->max_profile.numGlyphs )
184 {
185 error = FT_THROW( Invalid_File_Format );
186 goto Exit;
187 }
188
189 /* load the indices */
190 {
191 FT_Int n;
192
193
194 if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) ||
195 FT_FRAME_ENTER( num_glyphs * 2L ) )
196 goto Fail;
197
198 for ( n = 0; n < num_glyphs; n++ )
199 glyph_indices[n] = FT_GET_USHORT();
200
201 FT_FRAME_EXIT();
202 }
203
204 /* compute number of names stored in table */
205 {
206 FT_Int n;
207
208
209 num_names = 0;
210
211 for ( n = 0; n < num_glyphs; n++ )
212 {
213 FT_Int idx;
214
215
216 idx = glyph_indices[n];
217 if ( idx >= 258 )
218 {
219 idx -= 257;
220 if ( idx > num_names )
221 num_names = (FT_UShort)idx;
222 }
223 }
224 }
225
226 /* now load the name strings */
227 {
228 FT_UShort n;
229
230
231 if ( FT_NEW_ARRAY( name_strings, num_names ) )
232 goto Fail;
233
234 for ( n = 0; n < num_names; n++ )
235 {
236 FT_UInt len;
237
238
239 if ( FT_STREAM_POS() >= post_limit )
240 break;
241 else
242 {
243 FT_TRACE6(( "load_format_20: %d byte left in post table\n",
244 post_limit - FT_STREAM_POS() ));
245
246 if ( FT_READ_BYTE( len ) )
247 goto Fail1;
248 }
249
250 if ( len > post_limit ||
251 FT_STREAM_POS() > post_limit - len )
252 {
253 FT_Int d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS();
254
255
256 FT_ERROR(( "load_format_20:"
257 " exceeding string length (%d),"
258 " truncating at end of post table (%d byte left)\n",
259 len, d ));
260 len = (FT_UInt)FT_MAX( 0, d );
261 }
262
263 if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) ||
264 FT_STREAM_READ( name_strings[n], len ) )
265 goto Fail1;
266
267 name_strings[n][len] = '\0';
268 }
269
270 if ( n < num_names )
271 {
272 FT_ERROR(( "load_format_20:"
273 " all entries in post table are already parsed,"
274 " using NULL names for gid %d - %d\n",
275 n, num_names - 1 ));
276 for ( ; n < num_names; n++ )
277 if ( FT_NEW_ARRAY( name_strings[n], 1 ) )
278 goto Fail1;
279 else
280 name_strings[n][0] = '\0';
281 }
282 }
283
284 /* all right, set table fields and exit successfully */
285 {
286 TT_Post_20 table = &face->postscript_names.names.format_20;
287
288
289 table->num_glyphs = (FT_UShort)num_glyphs;
290 table->num_names = (FT_UShort)num_names;
291 table->glyph_indices = glyph_indices;
292 table->glyph_names = name_strings;
293 }
294 return FT_Err_Ok;
295
296 Fail1:
297 {
298 FT_UShort n;
299
300
301 for ( n = 0; n < num_names; n++ )
302 FT_FREE( name_strings[n] );
303 }
304
305 Fail:
306 FT_FREE( name_strings );
307 FT_FREE( glyph_indices );
308
309 Exit:
310 return error;
311 }
312
313
314 static FT_Error
315 load_format_25( TT_Face face,
316 FT_Stream stream,
317 FT_ULong post_limit )
318 {
319 FT_Memory memory = stream->memory;
320 FT_Error error;
321
322 FT_Int num_glyphs;
323 FT_Char* offset_table = NULL;
324
325 FT_UNUSED( post_limit );
326
327
328 if ( FT_READ_USHORT( num_glyphs ) )
329 goto Exit;
330
331 /* check the number of glyphs */
332 if ( num_glyphs > face->max_profile.numGlyphs ||
333 num_glyphs > 258 ||
334 num_glyphs < 1 )
335 {
336 error = FT_THROW( Invalid_File_Format );
337 goto Exit;
338 }
339
340 if ( FT_NEW_ARRAY( offset_table, num_glyphs ) ||
341 FT_STREAM_READ( offset_table, num_glyphs ) )
342 goto Fail;
343
344 /* now check the offset table */
345 {
346 FT_Int n;
347
348
349 for ( n = 0; n < num_glyphs; n++ )
350 {
351 FT_Long idx = (FT_Long)n + offset_table[n];
352
353
354 if ( idx < 0 || idx > num_glyphs )
355 {
356 error = FT_THROW( Invalid_File_Format );
357 goto Fail;
358 }
359 }
360 }
361
362 /* OK, set table fields and exit successfully */
363 {
364 TT_Post_25 table = &face->postscript_names.names.format_25;
365
366
367 table->num_glyphs = (FT_UShort)num_glyphs;
368 table->offsets = offset_table;
369 }
370
371 return FT_Err_Ok;
372
373 Fail:
374 FT_FREE( offset_table );
375
376 Exit:
377 return error;
378 }
379
380
381 static FT_Error
382 load_post_names( TT_Face face )
383 {
384 FT_Stream stream;
385 FT_Error error;
386 FT_Fixed format;
387 FT_ULong post_len;
388 FT_ULong post_limit;
389
390
391 /* get a stream for the face's resource */
392 stream = face->root.stream;
393
394 /* seek to the beginning of the PS names table */
395 error = face->goto_table( face, TTAG_post, stream, &post_len );
396 if ( error )
397 goto Exit;
398
399 post_limit = FT_STREAM_POS() + post_len;
400
401 format = face->postscript.FormatType;
402
403 /* go to beginning of subtable */
404 if ( FT_STREAM_SKIP( 32 ) )
405 goto Exit;
406
407 /* now read postscript table */
408 if ( format == 0x00020000L )
409 error = load_format_20( face, stream, post_limit );
410 else if ( format == 0x00025000L )
411 error = load_format_25( face, stream, post_limit );
412 else
413 error = FT_THROW( Invalid_File_Format );
414
415 face->postscript_names.loaded = 1;
416
417 Exit:
418 return error;
419 }
420
421
422 FT_LOCAL_DEF( void )
423 tt_face_free_ps_names( TT_Face face )
424 {
425 FT_Memory memory = face->root.memory;
426 TT_Post_Names names = &face->postscript_names;
427 FT_Fixed format;
428
429
430 if ( names->loaded )
431 {
432 format = face->postscript.FormatType;
433
434 if ( format == 0x00020000L )
435 {
436 TT_Post_20 table = &names->names.format_20;
437 FT_UShort n;
438
439
440 FT_FREE( table->glyph_indices );
441 table->num_glyphs = 0;
442
443 for ( n = 0; n < table->num_names; n++ )
444 FT_FREE( table->glyph_names[n] );
445
446 FT_FREE( table->glyph_names );
447 table->num_names = 0;
448 }
449 else if ( format == 0x00025000L )
450 {
451 TT_Post_25 table = &names->names.format_25;
452
453
454 FT_FREE( table->offsets );
455 table->num_glyphs = 0;
456 }
457 }
458 names->loaded = 0;
459 }
460
461
462 /**************************************************************************
463 *
464 * @Function:
465 * tt_face_get_ps_name
466 *
467 * @Description:
468 * Get the PostScript glyph name of a glyph.
469 *
470 * @Input:
471 * face ::
472 * A handle to the parent face.
473 *
474 * idx ::
475 * The glyph index.
476 *
477 * @InOut:
478 * PSname ::
479 * The address of a string pointer. Undefined in case of
480 * error, otherwise it is a pointer to the glyph name.
481 *
482 * You must not modify the returned string!
483 *
484 * @Output:
485 * FreeType error code. 0 means success.
486 */
487 FT_LOCAL_DEF( FT_Error )
488 tt_face_get_ps_name( TT_Face face,
489 FT_UInt idx,
490 FT_String** PSname )
491 {
492 FT_Error error;
493 TT_Post_Names names;
494 FT_Fixed format;
495
496#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
497 FT_Service_PsCMaps psnames;
498#endif
499
500
501 if ( !face )
502 return FT_THROW( Invalid_Face_Handle );
503
504 if ( idx >= (FT_UInt)face->max_profile.numGlyphs )
505 return FT_THROW( Invalid_Glyph_Index );
506
507#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
508 psnames = (FT_Service_PsCMaps)face->psnames;
509 if ( !psnames )
510 return FT_THROW( Unimplemented_Feature );
511#endif
512
513 names = &face->postscript_names;
514
515 /* `.notdef' by default */
516 *PSname = MAC_NAME( 0 );
517
518 format = face->postscript.FormatType;
519
520 if ( format == 0x00010000L )
521 {
522 if ( idx < 258 ) /* paranoid checking */
523 *PSname = MAC_NAME( idx );
524 }
525 else if ( format == 0x00020000L )
526 {
527 TT_Post_20 table = &names->names.format_20;
528
529
530 if ( !names->loaded )
531 {
532 error = load_post_names( face );
533 if ( error )
534 goto End;
535 }
536
537 if ( idx < (FT_UInt)table->num_glyphs )
538 {
539 FT_UShort name_index = table->glyph_indices[idx];
540
541
542 if ( name_index < 258 )
543 *PSname = MAC_NAME( name_index );
544 else
545 *PSname = (FT_String*)table->glyph_names[name_index - 258];
546 }
547 }
548 else if ( format == 0x00025000L )
549 {
550 TT_Post_25 table = &names->names.format_25;
551
552
553 if ( !names->loaded )
554 {
555 error = load_post_names( face );
556 if ( error )
557 goto End;
558 }
559
560 if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */
561 *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] );
562 }
563
564 /* nothing to do for format == 0x00030000L */
565
566 End:
567 return FT_Err_Ok;
568 }
569
570#else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
571
572 /* ANSI C doesn't like empty source files */
573 typedef int _tt_post_dummy;
574
575#endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
576
577
578/* END */
579