Coverage Report

Created: 2021-08-22 09:07

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