1/***************************************************************************/
2/*                                                                         */
3/*  ttpload.c                                                              */
4/*                                                                         */
5/*    TrueType-specific tables loader (body).                              */
6/*                                                                         */
7/*  Copyright 1996-2017 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#include FT_INTERNAL_OBJECTS_H
22#include FT_INTERNAL_STREAM_H
23#include FT_TRUETYPE_TAGS_H
24
25#include "ttpload.h"
26
27#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
28#include "ttgxvar.h"
29#endif
30
31#include "tterrors.h"
32
33
34  /*************************************************************************/
35  /*                                                                       */
36  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
37  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
38  /* messages during execution.                                            */
39  /*                                                                       */
40#undef  FT_COMPONENT
41#define FT_COMPONENT  trace_ttpload
42
43
44  /*************************************************************************/
45  /*                                                                       */
46  /* <Function>                                                            */
47  /*    tt_face_load_loca                                                  */
48  /*                                                                       */
49  /* <Description>                                                         */
50  /*    Load the locations table.                                          */
51  /*                                                                       */
52  /* <InOut>                                                               */
53  /*    face   :: A handle to the target face object.                      */
54  /*                                                                       */
55  /* <Input>                                                               */
56  /*    stream :: The input stream.                                        */
57  /*                                                                       */
58  /* <Return>                                                              */
59  /*    FreeType error code.  0 means success.                             */
60  /*                                                                       */
61  FT_LOCAL_DEF( FT_Error )
62  tt_face_load_loca( TT_Face    face,
63                     FT_Stream  stream )
64  {
65    FT_Error  error;
66    FT_ULong  table_len;
67    FT_Int    shift;
68
69
70    /* we need the size of the `glyf' table for malformed `loca' tables */
71    error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len );
72
73    /* it is possible that a font doesn't have a glyf table at all */
74    /* or its size is zero                                         */
75    if ( FT_ERR_EQ( error, Table_Missing ) )
76    {
77      face->glyf_len    = 0;
78      face->glyf_offset = 0;
79    }
80    else if ( error )
81      goto Exit;
82    else
83    {
84#ifdef FT_CONFIG_OPTION_INCREMENTAL
85      if ( face->root.internal->incremental_interface )
86        face->glyf_offset = 0;
87      else
88#endif
89        face->glyf_offset = FT_STREAM_POS();
90    }
91
92    FT_TRACE2(( "Locations " ));
93    error = face->goto_table( face, TTAG_loca, stream, &table_len );
94    if ( error )
95    {
96      error = FT_THROW( Locations_Missing );
97      goto Exit;
98    }
99
100    if ( face->header.Index_To_Loc_Format != 0 )
101    {
102      shift = 2;
103
104      if ( table_len >= 0x40000L )
105      {
106        FT_TRACE2(( "table too large\n" ));
107        table_len = 0x3FFFFL;
108      }
109      face->num_locations = table_len >> shift;
110    }
111    else
112    {
113      shift = 1;
114
115      if ( table_len >= 0x20000L )
116      {
117        FT_TRACE2(( "table too large\n" ));
118        table_len = 0x1FFFFL;
119      }
120      face->num_locations = table_len >> shift;
121    }
122
123    if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 )
124    {
125      FT_TRACE2(( "glyph count mismatch!  loca: %d, maxp: %d\n",
126                  face->num_locations - 1, face->root.num_glyphs ));
127
128      /* we only handle the case where `maxp' gives a larger value */
129      if ( face->num_locations <= (FT_ULong)face->root.num_glyphs )
130      {
131        FT_ULong  new_loca_len =
132                    ( (FT_ULong)face->root.num_glyphs + 1 ) << shift;
133
134        TT_Table  entry = face->dir_tables;
135        TT_Table  limit = entry + face->num_tables;
136
137        FT_Long  pos   = (FT_Long)FT_STREAM_POS();
138        FT_Long  dist  = 0x7FFFFFFFL;
139        FT_Bool  found = 0;
140
141
142        /* compute the distance to next table in font file */
143        for ( ; entry < limit; entry++ )
144        {
145          FT_Long  diff = (FT_Long)entry->Offset - pos;
146
147
148          if ( diff > 0 && diff < dist )
149          {
150            dist  = diff;
151            found = 1;
152          }
153        }
154
155        if ( !found )
156        {
157          /* `loca' is the last table */
158          dist = (FT_Long)stream->size - pos;
159        }
160
161        if ( new_loca_len <= (FT_ULong)dist )
162        {
163          face->num_locations = (FT_ULong)face->root.num_glyphs + 1;
164          table_len           = new_loca_len;
165
166          FT_TRACE2(( "adjusting num_locations to %d\n",
167                      face->num_locations ));
168        }
169        else
170        {
171          face->root.num_glyphs = face->num_locations
172                                    ? (FT_Long)face->num_locations - 1 : 0;
173
174          FT_TRACE2(( "adjusting num_glyphs to %d\n",
175                      face->root.num_glyphs ));
176        }
177      }
178    }
179
180    /*
181     * Extract the frame.  We don't need to decompress it since
182     * we are able to parse it directly.
183     */
184    if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) )
185      goto Exit;
186
187    FT_TRACE2(( "loaded\n" ));
188
189  Exit:
190    return error;
191  }
192
193
194  FT_LOCAL_DEF( FT_ULong )
195  tt_face_get_location( TT_Face   face,
196                        FT_UInt   gindex,
197                        FT_UInt  *asize )
198  {
199    FT_ULong  pos1, pos2;
200    FT_Byte*  p;
201    FT_Byte*  p_limit;
202
203
204    pos1 = pos2 = 0;
205
206    if ( gindex < face->num_locations )
207    {
208      if ( face->header.Index_To_Loc_Format != 0 )
209      {
210        p       = face->glyph_locations + gindex * 4;
211        p_limit = face->glyph_locations + face->num_locations * 4;
212
213        pos1 = FT_NEXT_ULONG( p );
214        pos2 = pos1;
215
216        if ( p + 4 <= p_limit )
217          pos2 = FT_NEXT_ULONG( p );
218      }
219      else
220      {
221        p       = face->glyph_locations + gindex * 2;
222        p_limit = face->glyph_locations + face->num_locations * 2;
223
224        pos1 = FT_NEXT_USHORT( p );
225        pos2 = pos1;
226
227        if ( p + 2 <= p_limit )
228          pos2 = FT_NEXT_USHORT( p );
229
230        pos1 <<= 1;
231        pos2 <<= 1;
232      }
233    }
234
235    /* Check broken location data. */
236    if ( pos1 > face->glyf_len )
237    {
238      FT_TRACE1(( "tt_face_get_location:"
239                  " too large offset (0x%08lx) found for glyph index %ld,\n"
240                  "                     "
241                  " exceeding the end of `glyf' table (0x%08lx)\n",
242                  pos1, gindex, face->glyf_len ));
243      *asize = 0;
244      return 0;
245    }
246
247    if ( pos2 > face->glyf_len )
248    {
249      /* We try to sanitize the last `loca' entry. */
250      if ( gindex == face->num_locations - 1 )
251      {
252        FT_TRACE1(( "tt_face_get_location:"
253                    " too large offset (0x%08lx) found for glyph index %ld,\n"
254                    "                     "
255                    " truncating at the end of `glyf' table (0x%08lx)\n",
256                    pos2, gindex + 1, face->glyf_len ));
257        pos2 = face->glyf_len;
258      }
259      else
260      {
261        FT_TRACE1(( "tt_face_get_location:"
262                    " too large offset (0x%08lx) found for glyph index %ld,\n"
263                    "                     "
264                    " exceeding the end of `glyf' table (0x%08lx)\n",
265                    pos2, gindex + 1, face->glyf_len ));
266        *asize = 0;
267        return 0;
268      }
269    }
270
271    /* The `loca' table must be ordered; it refers to the length of */
272    /* an entry as the difference between the current and the next  */
273    /* position.  However, there do exist (malformed) fonts which   */
274    /* don't obey this rule, so we are only able to provide an      */
275    /* upper bound for the size.                                    */
276    /*                                                              */
277    /* We get (intentionally) a wrong, non-zero result in case the  */
278    /* `glyf' table is missing.                                     */
279    if ( pos2 >= pos1 )
280      *asize = (FT_UInt)( pos2 - pos1 );
281    else
282      *asize = (FT_UInt)( face->glyf_len - pos1 );
283
284    return pos1;
285  }
286
287
288  FT_LOCAL_DEF( void )
289  tt_face_done_loca( TT_Face  face )
290  {
291    FT_Stream  stream = face->root.stream;
292
293
294    FT_FRAME_RELEASE( face->glyph_locations );
295    face->num_locations = 0;
296  }
297
298
299
300  /*************************************************************************/
301  /*                                                                       */
302  /* <Function>                                                            */
303  /*    tt_face_load_cvt                                                   */
304  /*                                                                       */
305  /* <Description>                                                         */
306  /*    Load the control value table into a face object.                   */
307  /*                                                                       */
308  /* <InOut>                                                               */
309  /*    face   :: A handle to the target face object.                      */
310  /*                                                                       */
311  /* <Input>                                                               */
312  /*    stream :: A handle to the input stream.                            */
313  /*                                                                       */
314  /* <Return>                                                              */
315  /*    FreeType error code.  0 means success.                             */
316  /*                                                                       */
317  FT_LOCAL_DEF( FT_Error )
318  tt_face_load_cvt( TT_Face    face,
319                    FT_Stream  stream )
320  {
321#ifdef TT_USE_BYTECODE_INTERPRETER
322
323    FT_Error   error;
324    FT_Memory  memory = stream->memory;
325    FT_ULong   table_len;
326
327
328    FT_TRACE2(( "CVT " ));
329
330    error = face->goto_table( face, TTAG_cvt, stream, &table_len );
331    if ( error )
332    {
333      FT_TRACE2(( "is missing\n" ));
334
335      face->cvt_size = 0;
336      face->cvt      = NULL;
337      error          = FT_Err_Ok;
338
339      goto Exit;
340    }
341
342    face->cvt_size = table_len / 2;
343
344    if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
345      goto Exit;
346
347    if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
348      goto Exit;
349
350    {
351      FT_Short*  cur   = face->cvt;
352      FT_Short*  limit = cur + face->cvt_size;
353
354
355      for ( ; cur < limit; cur++ )
356        *cur = FT_GET_SHORT();
357    }
358
359    FT_FRAME_EXIT();
360    FT_TRACE2(( "loaded\n" ));
361
362#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
363    if ( face->doblend )
364      error = tt_face_vary_cvt( face, stream );
365#endif
366
367  Exit:
368    return error;
369
370#else /* !TT_USE_BYTECODE_INTERPRETER */
371
372    FT_UNUSED( face   );
373    FT_UNUSED( stream );
374
375    return FT_Err_Ok;
376
377#endif
378  }
379
380
381  /*************************************************************************/
382  /*                                                                       */
383  /* <Function>                                                            */
384  /*    tt_face_load_fpgm                                                  */
385  /*                                                                       */
386  /* <Description>                                                         */
387  /*    Load the font program.                                             */
388  /*                                                                       */
389  /* <InOut>                                                               */
390  /*    face   :: A handle to the target face object.                      */
391  /*                                                                       */
392  /* <Input>                                                               */
393  /*    stream :: A handle to the input stream.                            */
394  /*                                                                       */
395  /* <Return>                                                              */
396  /*    FreeType error code.  0 means success.                             */
397  /*                                                                       */
398  FT_LOCAL_DEF( FT_Error )
399  tt_face_load_fpgm( TT_Face    face,
400                     FT_Stream  stream )
401  {
402#ifdef TT_USE_BYTECODE_INTERPRETER
403
404    FT_Error  error;
405    FT_ULong  table_len;
406
407
408    FT_TRACE2(( "Font program " ));
409
410    /* The font program is optional */
411    error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
412    if ( error )
413    {
414      face->font_program      = NULL;
415      face->font_program_size = 0;
416      error                   = FT_Err_Ok;
417
418      FT_TRACE2(( "is missing\n" ));
419    }
420    else
421    {
422      face->font_program_size = table_len;
423      if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
424        goto Exit;
425
426      FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
427    }
428
429  Exit:
430    return error;
431
432#else /* !TT_USE_BYTECODE_INTERPRETER */
433
434    FT_UNUSED( face   );
435    FT_UNUSED( stream );
436
437    return FT_Err_Ok;
438
439#endif
440  }
441
442
443  /*************************************************************************/
444  /*                                                                       */
445  /* <Function>                                                            */
446  /*    tt_face_load_prep                                                  */
447  /*                                                                       */
448  /* <Description>                                                         */
449  /*    Load the cvt program.                                              */
450  /*                                                                       */
451  /* <InOut>                                                               */
452  /*    face   :: A handle to the target face object.                      */
453  /*                                                                       */
454  /* <Input>                                                               */
455  /*    stream :: A handle to the input stream.                            */
456  /*                                                                       */
457  /* <Return>                                                              */
458  /*    FreeType error code.  0 means success.                             */
459  /*                                                                       */
460  FT_LOCAL_DEF( FT_Error )
461  tt_face_load_prep( TT_Face    face,
462                     FT_Stream  stream )
463  {
464#ifdef TT_USE_BYTECODE_INTERPRETER
465
466    FT_Error  error;
467    FT_ULong  table_len;
468
469
470    FT_TRACE2(( "Prep program " ));
471
472    error = face->goto_table( face, TTAG_prep, stream, &table_len );
473    if ( error )
474    {
475      face->cvt_program      = NULL;
476      face->cvt_program_size = 0;
477      error                  = FT_Err_Ok;
478
479      FT_TRACE2(( "is missing\n" ));
480    }
481    else
482    {
483      face->cvt_program_size = table_len;
484      if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
485        goto Exit;
486
487      FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
488    }
489
490  Exit:
491    return error;
492
493#else /* !TT_USE_BYTECODE_INTERPRETER */
494
495    FT_UNUSED( face   );
496    FT_UNUSED( stream );
497
498    return FT_Err_Ok;
499
500#endif
501  }
502
503
504  /*************************************************************************/
505  /*                                                                       */
506  /* <Function>                                                            */
507  /*    tt_face_load_hdmx                                                  */
508  /*                                                                       */
509  /* <Description>                                                         */
510  /*    Load the `hdmx' table into the face object.                        */
511  /*                                                                       */
512  /* <Input>                                                               */
513  /*    face   :: A handle to the target face object.                      */
514  /*                                                                       */
515  /*    stream :: A handle to the input stream.                            */
516  /*                                                                       */
517  /* <Return>                                                              */
518  /*    FreeType error code.  0 means success.                             */
519  /*                                                                       */
520
521  FT_LOCAL_DEF( FT_Error )
522  tt_face_load_hdmx( TT_Face    face,
523                     FT_Stream  stream )
524  {
525    FT_Error   error;
526    FT_Memory  memory = stream->memory;
527    FT_UInt    nn, num_records;
528    FT_ULong   table_size, record_size;
529    FT_Byte*   p;
530    FT_Byte*   limit;
531
532
533    /* this table is optional */
534    error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
535    if ( error || table_size < 8 )
536      return FT_Err_Ok;
537
538    if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
539      goto Exit;
540
541    p     = face->hdmx_table;
542    limit = p + table_size;
543
544    /* Given that `hdmx' tables are losing its importance (for example, */
545    /* variation fonts introduced in OpenType 1.8 must not have this    */
546    /* table) we no longer test for a correct `version' field.          */
547    p          += 2;
548    num_records = FT_NEXT_USHORT( p );
549    record_size = FT_NEXT_ULONG( p );
550
551    /* The maximum number of bytes in an hdmx device record is the */
552    /* maximum number of glyphs + 2; this is 0xFFFF + 2, thus      */
553    /* explaining why `record_size' is a long (which we read as    */
554    /* unsigned long for convenience).  In practice, two bytes are */
555    /* sufficient to hold the size value.                          */
556    /*                                                             */
557    /* There are at least two fonts, HANNOM-A and HANNOM-B version */
558    /* 2.0 (2005), which get this wrong: The upper two bytes of    */
559    /* the size value are set to 0xFF instead of 0x00.  We catch   */
560    /* and fix this.                                               */
561
562    if ( record_size >= 0xFFFF0000UL )
563      record_size &= 0xFFFFU;
564
565    /* The limit for `num_records' is a heuristic value. */
566    if ( num_records > 255              ||
567         ( num_records > 0            &&
568           ( record_size > 0x10001L ||
569             record_size < 4        ) ) )
570    {
571      error = FT_THROW( Invalid_File_Format );
572      goto Fail;
573    }
574
575    if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
576      goto Fail;
577
578    for ( nn = 0; nn < num_records; nn++ )
579    {
580      if ( p + record_size > limit )
581        break;
582
583      face->hdmx_record_sizes[nn] = p[0];
584      p                          += record_size;
585    }
586
587    face->hdmx_record_count = nn;
588    face->hdmx_table_size   = table_size;
589    face->hdmx_record_size  = record_size;
590
591  Exit:
592    return error;
593
594  Fail:
595    FT_FRAME_RELEASE( face->hdmx_table );
596    face->hdmx_table_size = 0;
597    goto Exit;
598  }
599
600
601  FT_LOCAL_DEF( void )
602  tt_face_free_hdmx( TT_Face  face )
603  {
604    FT_Stream  stream = face->root.stream;
605    FT_Memory  memory = stream->memory;
606
607
608    FT_FREE( face->hdmx_record_sizes );
609    FT_FRAME_RELEASE( face->hdmx_table );
610  }
611
612
613  /*************************************************************************/
614  /*                                                                       */
615  /* Return the advance width table for a given pixel size if it is found  */
616  /* in the font's `hdmx' table (if any).                                  */
617  /*                                                                       */
618  FT_LOCAL_DEF( FT_Byte* )
619  tt_face_get_device_metrics( TT_Face  face,
620                              FT_UInt  ppem,
621                              FT_UInt  gindex )
622  {
623    FT_UInt   nn;
624    FT_Byte*  result      = NULL;
625    FT_ULong  record_size = face->hdmx_record_size;
626    FT_Byte*  record      = face->hdmx_table + 8;
627
628
629    for ( nn = 0; nn < face->hdmx_record_count; nn++ )
630      if ( face->hdmx_record_sizes[nn] == ppem )
631      {
632        gindex += 2;
633        if ( gindex < record_size )
634          result = record + nn * record_size + gindex;
635        break;
636      }
637
638    return result;
639  }
640
641
642/* END */
643