1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  ttpload.c                                                              */
   4 /*                                                                         */
   5 /*    TrueType-specific tables loader (body).                              */
   6 /*                                                                         */
   7 /*  Copyright 1996-2018 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 - 2 )
 251       {
 252         FT_TRACE1(( "tt_face_get_location:"
 253                     " too large size (%ld bytes) found for glyph index %ld,\n"
 254                     "                     "
 255                     " truncating at the end of `glyf' table to %ld bytes\n",
 256                     pos2 - pos1, gindex, face->glyf_len - pos1 ));
 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 */