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