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
load_format_20(TT_Face face,FT_Stream stream,FT_ULong post_limit)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
load_format_25(TT_Face face,FT_Stream stream,FT_ULong post_limit)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
load_post_names(TT_Face face)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 )
tt_face_free_ps_names(TT_Face face)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 )
tt_face_get_ps_name(TT_Face face,FT_UInt idx,FT_String ** PSname)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