tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sfwoff2.c (66586B)


      1 /****************************************************************************
      2 *
      3 * sfwoff2.c
      4 *
      5 *   WOFF2 format management (base).
      6 *
      7 * Copyright (C) 2019-2025 by
      8 * Nikhil Ramakrishnan, 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 #include "sfwoff2.h"
     19 #include "woff2tags.h"
     20 #include <freetype/tttags.h>
     21 #include <freetype/internal/ftcalc.h>
     22 #include <freetype/internal/ftdebug.h>
     23 #include <freetype/internal/ftstream.h>
     24 
     25 
     26 #ifdef FT_CONFIG_OPTION_USE_BROTLI
     27 
     28 #include <brotli/decode.h>
     29 
     30 
     31  /**************************************************************************
     32   *
     33   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     34   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     35   * messages during execution.
     36   */
     37 #undef  FT_COMPONENT
     38 #define FT_COMPONENT  sfwoff2
     39 
     40  /* An arbitrary, heuristic size limit (67MByte) for expanded WOFF2 data. */
     41 #define MAX_SFNT_SIZE  ( 1 << 26 )
     42 
     43 #define READ_255USHORT( var )  FT_SET_ERROR( Read255UShort( stream, &var ) )
     44 
     45 #define READ_BASE128( var )    FT_SET_ERROR( ReadBase128( stream, &var ) )
     46 
     47  /* `var' should be FT_ULong */
     48 #define ROUND4( var )          ( ( var + 3 ) & ~3UL )
     49 
     50 #define WRITE_USHORT( p, v )                \
     51          do                                \
     52          {                                 \
     53            *(p)++ = (FT_Byte)( (v) >> 8 ); \
     54            *(p)++ = (FT_Byte)( (v) >> 0 ); \
     55                                            \
     56          } while ( 0 )
     57 
     58 #define WRITE_ULONG( p, v )                  \
     59          do                                 \
     60          {                                  \
     61            *(p)++ = (FT_Byte)( (v) >> 24 ); \
     62            *(p)++ = (FT_Byte)( (v) >> 16 ); \
     63            *(p)++ = (FT_Byte)( (v) >>  8 ); \
     64            *(p)++ = (FT_Byte)( (v) >>  0 ); \
     65                                             \
     66          } while ( 0 )
     67 
     68 #define WRITE_SHORT( p, v )                 \
     69          do                                \
     70          {                                 \
     71            *(p)++ = (FT_Byte)( (v) >> 8 ); \
     72            *(p)++ = (FT_Byte)( (v) >> 0 ); \
     73                                            \
     74          } while ( 0 )
     75 
     76 #define WRITE_SFNT_BUF( buf, s ) \
     77          write_buf( &sfnt, sfnt_size, &dest_offset, buf, s, memory )
     78 
     79 #define WRITE_SFNT_BUF_AT( offset, buf, s ) \
     80          write_buf( &sfnt, sfnt_size, &offset, buf, s, memory )
     81 
     82 #define N_CONTOUR_STREAM    0
     83 #define N_POINTS_STREAM     1
     84 #define FLAG_STREAM         2
     85 #define GLYPH_STREAM        3
     86 #define COMPOSITE_STREAM    4
     87 #define BBOX_STREAM         5
     88 #define INSTRUCTION_STREAM  6
     89 
     90 #define HAVE_OVERLAP_SIMPLE_BITMAP  0x1
     91 
     92 
     93  static void
     94  stream_close( FT_Stream  stream )
     95  {
     96    FT_Memory  memory = stream->memory;
     97 
     98 
     99    FT_FREE( stream->base );
    100 
    101    stream->size  = 0;
    102    stream->close = NULL;
    103  }
    104 
    105 
    106  FT_COMPARE_DEF( int )
    107  compare_tags( const void*  a,
    108                const void*  b )
    109  {
    110    WOFF2_Table  table1 = *(WOFF2_Table*)a;
    111    WOFF2_Table  table2 = *(WOFF2_Table*)b;
    112 
    113    FT_Tag  tag1 = table1->Tag;
    114    FT_Tag  tag2 = table2->Tag;
    115 
    116 
    117    if ( tag1 > tag2 )
    118      return 1;
    119    else if ( tag1 < tag2 )
    120      return -1;
    121    else
    122      return 0;
    123  }
    124 
    125 
    126  static FT_Error
    127  Read255UShort( FT_Stream   stream,
    128                 FT_UShort*  value )
    129  {
    130    const FT_Byte    oneMoreByteCode1 = 255;
    131    const FT_Byte    oneMoreByteCode2 = 254;
    132    const FT_Byte    wordCode         = 253;
    133    const FT_UShort  lowestUCode      = 253;
    134 
    135    FT_Error   error        = FT_Err_Ok;
    136    FT_Byte    code;
    137    FT_Byte    result_byte  = 0;
    138    FT_UShort  result_short = 0;
    139 
    140 
    141    if ( FT_READ_BYTE( code ) )
    142      return error;
    143    if ( code == wordCode )
    144    {
    145      /* Read next two bytes and store `FT_UShort' value. */
    146      if ( FT_READ_USHORT( result_short ) )
    147        return error;
    148      *value = result_short;
    149      return FT_Err_Ok;
    150    }
    151    else if ( code == oneMoreByteCode1 )
    152    {
    153      if ( FT_READ_BYTE( result_byte ) )
    154        return error;
    155      *value = result_byte + lowestUCode;
    156      return FT_Err_Ok;
    157    }
    158    else if ( code == oneMoreByteCode2 )
    159    {
    160      if ( FT_READ_BYTE( result_byte ) )
    161        return error;
    162      *value = result_byte + lowestUCode * 2;
    163      return FT_Err_Ok;
    164    }
    165    else
    166    {
    167      *value = code;
    168      return FT_Err_Ok;
    169    }
    170  }
    171 
    172 
    173  static FT_Error
    174  ReadBase128( FT_Stream  stream,
    175               FT_ULong*  value )
    176  {
    177    FT_ULong  result = 0;
    178    FT_Int    i;
    179    FT_Byte   code;
    180    FT_Error  error  = FT_Err_Ok;
    181 
    182 
    183    for ( i = 0; i < 5; ++i )
    184    {
    185      code = 0;
    186      if ( FT_READ_BYTE( code ) )
    187        return error;
    188 
    189      /* Leading zeros are invalid. */
    190      if ( i == 0 && code == 0x80 )
    191        return FT_THROW( Invalid_Table );
    192 
    193      /* If any of top seven bits are set then we're about to overflow. */
    194      if ( result & 0xfe000000 )
    195        return FT_THROW( Invalid_Table );
    196 
    197      result = ( result << 7 ) | ( code & 0x7f );
    198 
    199      /* Spin until most significant bit of data byte is false. */
    200      if ( ( code & 0x80 ) == 0 )
    201      {
    202        *value = result;
    203        return FT_Err_Ok;
    204      }
    205    }
    206 
    207    /* Make sure not to exceed the size bound. */
    208    return FT_THROW( Invalid_Table );
    209  }
    210 
    211 
    212  /* Extend memory of `dst_bytes' buffer and copy data from `src'. */
    213  static FT_Error
    214  write_buf( FT_Byte**  dst_bytes,
    215             FT_ULong*  dst_size,
    216             FT_ULong*  offset,
    217             FT_Byte*   src,
    218             FT_ULong   size,
    219             FT_Memory  memory )
    220  {
    221    FT_Error  error = FT_Err_Ok;
    222    /* We are reallocating memory for `dst', so its pointer may change. */
    223    FT_Byte*  dst   = *dst_bytes;
    224 
    225 
    226    /* Check whether we are within limits. */
    227    if ( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE  )
    228      return FT_THROW( Array_Too_Large );
    229 
    230    /* Reallocate `dst'. */
    231    if ( ( *offset + size ) > *dst_size )
    232    {
    233      FT_TRACE6(( "Reallocating %lu to %lu.\n",
    234                  *dst_size, (*offset + size) ));
    235      if ( FT_QREALLOC( dst,
    236                        (FT_ULong)( *dst_size ),
    237                        (FT_ULong)( *offset + size ) ) )
    238        goto Exit;
    239 
    240      *dst_size = *offset + size;
    241    }
    242 
    243    /* Copy data. */
    244    ft_memcpy( dst + *offset, src, size );
    245 
    246    *offset += size;
    247    /* Set pointer of `dst' to its correct value. */
    248    *dst_bytes = dst;
    249 
    250  Exit:
    251    return error;
    252  }
    253 
    254 
    255  /* Pad buffer to closest multiple of 4. */
    256  static FT_Error
    257  pad4( FT_Byte**  sfnt_bytes,
    258        FT_ULong*  sfnt_size,
    259        FT_ULong*  out_offset,
    260        FT_Memory  memory )
    261  {
    262    FT_Byte*  sfnt        = *sfnt_bytes;
    263    FT_ULong  dest_offset = *out_offset;
    264 
    265    FT_Byte   zeroes[] = { 0, 0, 0 };
    266    FT_ULong  pad_bytes;
    267 
    268 
    269    if ( dest_offset + 3 < dest_offset )
    270      return FT_THROW( Invalid_Table );
    271 
    272    pad_bytes = ROUND4( dest_offset ) - dest_offset;
    273    if ( pad_bytes > 0 )
    274    {
    275      if ( WRITE_SFNT_BUF( &zeroes[0], pad_bytes ) )
    276        return FT_THROW( Invalid_Table );
    277    }
    278 
    279    *sfnt_bytes = sfnt;
    280    *out_offset = dest_offset;
    281    return FT_Err_Ok;
    282  }
    283 
    284 
    285  /* Calculate table checksum of `buf'. */
    286  static FT_ULong
    287  compute_ULong_sum( FT_Byte*  buf,
    288                     FT_ULong  size )
    289  {
    290    FT_ULong  checksum     = 0;
    291    FT_ULong  aligned_size = size & ~3UL;
    292    FT_ULong  i;
    293    FT_Int    shift;
    294 
    295 
    296    for ( i = 0; i < aligned_size; i += 4 )
    297      checksum += FT_NEXT_ULONG( buf );
    298 
    299    /* remaining bytes can be shifted and added one at a time */
    300    for ( shift = 24; i < size; i++, shift -= 8 )
    301      checksum += (FT_UInt32)FT_NEXT_BYTE( buf ) << shift;
    302 
    303    return checksum;
    304  }
    305 
    306 
    307  static FT_Error
    308  woff2_decompress( FT_Byte*        dst,
    309                    FT_ULong        dst_size,
    310                    const FT_Byte*  src,
    311                    FT_ULong        src_size )
    312  {
    313    /* this cast is only of importance on 32bit systems; */
    314    /* we don't validate it                              */
    315    FT_Offset            uncompressed_size = (FT_Offset)dst_size;
    316    BrotliDecoderResult  result;
    317 
    318 
    319    result = BrotliDecoderDecompress( src_size,
    320                                      src,
    321                                      &uncompressed_size,
    322                                      dst );
    323 
    324    if ( result != BROTLI_DECODER_RESULT_SUCCESS ||
    325         uncompressed_size != dst_size           )
    326    {
    327      FT_ERROR(( "woff2_decompress: Stream length mismatch.\n" ));
    328      return FT_THROW( Invalid_Table );
    329    }
    330 
    331    FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" ));
    332    return FT_Err_Ok;
    333  }
    334 
    335 
    336  static WOFF2_Table
    337  find_table( WOFF2_Table*  tables,
    338              FT_UShort     num_tables,
    339              FT_Tag        tag )
    340  {
    341    FT_Int  i;
    342 
    343 
    344    for ( i = 0; i < num_tables; i++ )
    345    {
    346      if ( tables[i]->Tag == tag )
    347        return tables[i];
    348    }
    349    return NULL;
    350  }
    351 
    352 
    353  /* Read `numberOfHMetrics' field from `hhea' table. */
    354  static FT_Error
    355  read_num_hmetrics( FT_Stream   stream,
    356                     FT_UShort*  num_hmetrics )
    357  {
    358    FT_Error   error = FT_Err_Ok;
    359    FT_UShort  num_metrics;
    360 
    361 
    362    if ( FT_STREAM_SKIP( 34 )  )
    363      return FT_THROW( Invalid_Table );
    364 
    365    if ( FT_READ_USHORT( num_metrics ) )
    366      return FT_THROW( Invalid_Table );
    367 
    368    *num_hmetrics = num_metrics;
    369 
    370    return error;
    371  }
    372 
    373 
    374  /* An auxiliary function for overflow-safe addition. */
    375  static FT_Int
    376  with_sign( FT_Byte  flag,
    377             FT_Int   base_val )
    378  {
    379    /* Precondition: 0 <= base_val < 65536 (to avoid overflow). */
    380    return ( flag & 1 ) ? base_val : -base_val;
    381  }
    382 
    383 
    384  /* An auxiliary function for overflow-safe addition. */
    385  static FT_Int
    386  safe_int_addition( FT_Int   a,
    387                     FT_Int   b,
    388                     FT_Int*  result )
    389  {
    390    if ( ( ( a > 0 ) && ( b > FT_INT_MAX - a ) ) ||
    391         ( ( a < 0 ) && ( b < FT_INT_MIN - a ) ) )
    392      return FT_THROW( Invalid_Table );
    393 
    394    *result = a + b;
    395    return FT_Err_Ok;
    396  }
    397 
    398 
    399  /*
    400   * Decode variable-length (flag, xCoordinate, yCoordinate) triplet for a
    401   * simple glyph.  See
    402   *
    403   *   https://www.w3.org/TR/WOFF2/#triplet_decoding
    404   */
    405  static FT_Error
    406  triplet_decode( const FT_Byte*  flags_in,
    407                  const FT_Byte*  in,
    408                  FT_ULong        in_size,
    409                  FT_ULong        n_points,
    410                  WOFF2_Point     result,
    411                  FT_ULong*       in_bytes_used )
    412  {
    413    FT_Int  x = 0;
    414    FT_Int  y = 0;
    415    FT_Int  dx;
    416    FT_Int  dy;
    417    FT_Int  b0, b1, b2;
    418 
    419    FT_ULong  triplet_index = 0;
    420    FT_ULong  data_bytes;
    421 
    422    FT_UInt  i;
    423 
    424 
    425    if ( n_points > in_size )
    426      return FT_THROW( Invalid_Table );
    427 
    428    for ( i = 0; i < n_points; ++i )
    429    {
    430      FT_Byte  flag     = flags_in[i];
    431      FT_Bool  on_curve = !( flag >> 7 );
    432 
    433 
    434      flag &= 0x7f;
    435      if ( flag < 84 )
    436        data_bytes = 1;
    437      else if ( flag < 120 )
    438        data_bytes = 2;
    439      else if ( flag < 124 )
    440        data_bytes = 3;
    441      else
    442        data_bytes = 4;
    443 
    444      /* Overflow checks */
    445      if ( triplet_index + data_bytes > in_size       ||
    446           triplet_index + data_bytes < triplet_index )
    447        return FT_THROW( Invalid_Table );
    448 
    449      if ( flag < 10 )
    450      {
    451        dx = 0;
    452        dy = with_sign( flag,
    453                        ( ( flag & 14 ) << 7 ) + in[triplet_index] );
    454      }
    455      else if ( flag < 20 )
    456      {
    457        dx = with_sign( flag,
    458                        ( ( ( flag - 10 ) & 14 ) << 7 ) +
    459                          in[triplet_index] );
    460        dy = 0;
    461      }
    462      else if ( flag < 84 )
    463      {
    464        b0 = flag - 20;
    465        b1 = in[triplet_index];
    466        dx = with_sign( flag,
    467                        1 + ( b0 & 0x30 ) + ( b1 >> 4 ) );
    468        dy = with_sign( flag >> 1,
    469                        1 + ( ( b0 & 0x0c ) << 2 ) + ( b1 & 0x0f ) );
    470      }
    471      else if ( flag < 120 )
    472      {
    473        b0 = flag - 84;
    474        dx = with_sign( flag,
    475                        1 + ( ( b0 / 12 ) << 8 ) + in[triplet_index] );
    476        dy = with_sign( flag >> 1,
    477                        1 + ( ( ( b0 % 12 ) >> 2 ) << 8 ) +
    478                          in[triplet_index + 1] );
    479      }
    480      else if ( flag < 124 )
    481      {
    482        b2 = in[triplet_index + 1];
    483        dx = with_sign( flag,
    484                        ( in[triplet_index] << 4 ) + ( b2 >> 4 ) );
    485        dy = with_sign( flag >> 1,
    486                        ( ( b2 & 0x0f ) << 8 ) + in[triplet_index + 2] );
    487      }
    488      else
    489      {
    490        dx = with_sign( flag,
    491                        ( in[triplet_index] << 8 ) +
    492                          in[triplet_index + 1] );
    493        dy = with_sign( flag >> 1,
    494                        ( in[triplet_index + 2] << 8 ) +
    495                          in[triplet_index + 3] );
    496      }
    497 
    498      triplet_index += data_bytes;
    499 
    500      if ( safe_int_addition( x, dx, &x ) )
    501        return FT_THROW( Invalid_Table );
    502 
    503      if ( safe_int_addition( y, dy, &y ) )
    504        return FT_THROW( Invalid_Table );
    505 
    506      result[i].x        = x;
    507      result[i].y        = y;
    508      result[i].on_curve = on_curve;
    509    }
    510 
    511    *in_bytes_used = triplet_index;
    512    return FT_Err_Ok;
    513  }
    514 
    515 
    516  /* Store decoded points in glyph buffer. */
    517  static FT_Error
    518  store_points( FT_ULong           n_points,
    519                const WOFF2_Point  points,
    520                FT_UShort          n_contours,
    521                FT_UShort          instruction_len,
    522                FT_Bool            have_overlap,
    523                FT_Byte*           dst,
    524                FT_ULong           dst_size,
    525                FT_ULong*          glyph_size )
    526  {
    527    FT_UInt   flag_offset  = 10 + ( 2 * n_contours ) + 2 + instruction_len;
    528    FT_Byte   last_flag    = 0xFFU;
    529    FT_Byte   repeat_count = 0;
    530    FT_Int    last_x       = 0;
    531    FT_Int    last_y       = 0;
    532    FT_UInt   x_bytes      = 0;
    533    FT_UInt   y_bytes      = 0;
    534    FT_UInt   xy_bytes;
    535    FT_UInt   i;
    536    FT_UInt   x_offset;
    537    FT_UInt   y_offset;
    538    FT_Byte*  pointer;
    539 
    540 
    541    for ( i = 0; i < n_points; ++i )
    542    {
    543      const WOFF2_PointRec  point = points[i];
    544 
    545      FT_Byte  flag = point.on_curve ? GLYF_ON_CURVE : 0;
    546      FT_Int   dx   = point.x - last_x;
    547      FT_Int   dy   = point.y - last_y;
    548 
    549 
    550      if ( i == 0 && have_overlap )
    551        flag |= GLYF_OVERLAP_SIMPLE;
    552 
    553      if ( dx == 0 )
    554        flag |= GLYF_THIS_X_IS_SAME;
    555      else if ( dx > -256 && dx < 256 )
    556      {
    557        flag |= GLYF_X_SHORT | ( dx > 0 ? GLYF_THIS_X_IS_SAME : 0 );
    558        x_bytes += 1;
    559      }
    560      else
    561        x_bytes += 2;
    562 
    563      if ( dy == 0 )
    564        flag |= GLYF_THIS_Y_IS_SAME;
    565      else if ( dy > -256 && dy < 256 )
    566      {
    567        flag |= GLYF_Y_SHORT | ( dy > 0 ? GLYF_THIS_Y_IS_SAME : 0 );
    568        y_bytes += 1;
    569      }
    570      else
    571        y_bytes += 2;
    572 
    573      if ( flag == last_flag && repeat_count != 255 )
    574      {
    575        dst[flag_offset - 1] |= GLYF_REPEAT;
    576        repeat_count++;
    577      }
    578      else
    579      {
    580        if ( repeat_count != 0 )
    581        {
    582          if ( flag_offset >= dst_size )
    583            return FT_THROW( Invalid_Table );
    584 
    585          dst[flag_offset++] = repeat_count;
    586        }
    587        if ( flag_offset >= dst_size )
    588          return FT_THROW( Invalid_Table );
    589 
    590        dst[flag_offset++] = flag;
    591        repeat_count       = 0;
    592      }
    593 
    594      last_x    = point.x;
    595      last_y    = point.y;
    596      last_flag = flag;
    597    }
    598 
    599    if ( repeat_count != 0 )
    600    {
    601      if ( flag_offset >= dst_size )
    602        return FT_THROW( Invalid_Table );
    603 
    604      dst[flag_offset++] = repeat_count;
    605    }
    606 
    607    xy_bytes = x_bytes + y_bytes;
    608    if ( xy_bytes < x_bytes                   ||
    609         flag_offset + xy_bytes < flag_offset ||
    610         flag_offset + xy_bytes > dst_size    )
    611      return FT_THROW( Invalid_Table );
    612 
    613    x_offset = flag_offset;
    614    y_offset = flag_offset + x_bytes;
    615    last_x = 0;
    616    last_y = 0;
    617 
    618    for ( i = 0; i < n_points; ++i )
    619    {
    620      FT_Int  dx = points[i].x - last_x;
    621      FT_Int  dy = points[i].y - last_y;
    622 
    623 
    624      if ( dx == 0 )
    625        ;
    626      else if ( dx > -256 && dx < 256 )
    627        dst[x_offset++] = (FT_Byte)FT_ABS( dx );
    628      else
    629      {
    630        pointer = dst + x_offset;
    631        WRITE_SHORT( pointer, dx );
    632        x_offset += 2;
    633      }
    634 
    635      last_x += dx;
    636 
    637      if ( dy == 0 )
    638        ;
    639      else if ( dy > -256 && dy < 256 )
    640        dst[y_offset++] = (FT_Byte)FT_ABS( dy );
    641      else
    642      {
    643        pointer = dst + y_offset;
    644        WRITE_SHORT( pointer, dy );
    645        y_offset += 2;
    646      }
    647 
    648      last_y += dy;
    649    }
    650 
    651    *glyph_size = y_offset;
    652    return FT_Err_Ok;
    653  }
    654 
    655 
    656  static void
    657  compute_bbox( FT_ULong           n_points,
    658                const WOFF2_Point  points,
    659                FT_Byte*           dst,
    660                FT_UShort*         src_x_min )
    661  {
    662    FT_Int  x_min = 0;
    663    FT_Int  y_min = 0;
    664    FT_Int  x_max = 0;
    665    FT_Int  y_max = 0;
    666 
    667    FT_UInt  i;
    668 
    669    FT_ULong  offset;
    670    FT_Byte*  pointer;
    671 
    672 
    673    if ( n_points > 0 )
    674    {
    675      x_min = points[0].x;
    676      y_min = points[0].y;
    677      x_max = points[0].x;
    678      y_max = points[0].y;
    679    }
    680 
    681    for ( i = 1; i < n_points; ++i )
    682    {
    683      FT_Int  x = points[i].x;
    684      FT_Int  y = points[i].y;
    685 
    686 
    687      x_min = FT_MIN( x, x_min );
    688      y_min = FT_MIN( y, y_min );
    689      x_max = FT_MAX( x, x_max );
    690      y_max = FT_MAX( y, y_max );
    691    }
    692 
    693    /* Write values to `glyf' record. */
    694    offset  = 2;
    695    pointer = dst + offset;
    696 
    697    WRITE_SHORT( pointer, x_min );
    698    WRITE_SHORT( pointer, y_min );
    699    WRITE_SHORT( pointer, x_max );
    700    WRITE_SHORT( pointer, y_max );
    701 
    702    *src_x_min = (FT_UShort)x_min;
    703  }
    704 
    705 
    706  static FT_Error
    707  compositeGlyph_size( FT_Stream  stream,
    708                       FT_ULong   offset,
    709                       FT_ULong*  size,
    710                       FT_Bool*   have_instructions )
    711  {
    712    FT_Error   error        = FT_Err_Ok;
    713    FT_ULong   start_offset = offset;
    714    FT_Bool    we_have_inst = FALSE;
    715    FT_UShort  flags        = FLAG_MORE_COMPONENTS;
    716 
    717 
    718    if ( FT_STREAM_SEEK( start_offset ) )
    719      goto Exit;
    720    while ( flags & FLAG_MORE_COMPONENTS )
    721    {
    722      FT_ULong  arg_size;
    723 
    724 
    725      if ( FT_READ_USHORT( flags ) )
    726        goto Exit;
    727      we_have_inst |= ( flags & FLAG_WE_HAVE_INSTRUCTIONS ) != 0;
    728      /* glyph index */
    729      arg_size = 2;
    730      if ( flags & FLAG_ARG_1_AND_2_ARE_WORDS )
    731        arg_size += 4;
    732      else
    733        arg_size += 2;
    734 
    735      if ( flags & FLAG_WE_HAVE_A_SCALE )
    736        arg_size += 2;
    737      else if ( flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE )
    738        arg_size += 4;
    739      else if ( flags & FLAG_WE_HAVE_A_TWO_BY_TWO )
    740        arg_size += 8;
    741 
    742      if ( FT_STREAM_SKIP( arg_size ) )
    743        goto Exit;
    744    }
    745 
    746    *size              = FT_STREAM_POS() - start_offset;
    747    *have_instructions = we_have_inst;
    748 
    749  Exit:
    750    return error;
    751  }
    752 
    753 
    754  /* Store loca values (provided by `reconstruct_glyf') to output stream. */
    755  static FT_Error
    756  store_loca( FT_ULong*  loca_values,
    757              FT_ULong   loca_values_size,
    758              FT_UShort  index_format,
    759              FT_ULong*  checksum,
    760              FT_Byte**  sfnt_bytes,
    761              FT_ULong*  sfnt_size,
    762              FT_ULong*  out_offset,
    763              FT_Memory  memory )
    764  {
    765    FT_Error  error       = FT_Err_Ok;
    766    FT_Byte*  sfnt        = *sfnt_bytes;
    767    FT_ULong  dest_offset = *out_offset;
    768 
    769    FT_Byte*  loca_buf = NULL;
    770    FT_Byte*  dst      = NULL;
    771 
    772    FT_UInt   i = 0;
    773    FT_ULong  loca_buf_size;
    774 
    775    const FT_ULong  offset_size = index_format ? 4 : 2;
    776 
    777 
    778    if ( ( loca_values_size << 2 ) >> 2 != loca_values_size )
    779      goto Fail;
    780 
    781    loca_buf_size = loca_values_size * offset_size;
    782    if ( FT_QALLOC( loca_buf, loca_buf_size ) )
    783      goto Fail;
    784 
    785    dst = loca_buf;
    786    for ( i = 0; i < loca_values_size; i++ )
    787    {
    788      FT_ULong  value = loca_values[i];
    789 
    790 
    791      if ( index_format )
    792        WRITE_ULONG( dst, value );
    793      else
    794        WRITE_USHORT( dst, ( value >> 1 ) );
    795    }
    796 
    797    *checksum = compute_ULong_sum( loca_buf, loca_buf_size );
    798    /* Write `loca' table to sfnt buffer. */
    799    if ( WRITE_SFNT_BUF( loca_buf, loca_buf_size ) )
    800      goto Fail;
    801 
    802    /* Set pointer `sfnt_bytes' to its correct value. */
    803    *sfnt_bytes = sfnt;
    804    *out_offset = dest_offset;
    805 
    806    FT_FREE( loca_buf );
    807    return error;
    808 
    809  Fail:
    810    if ( !error )
    811      error = FT_THROW( Invalid_Table );
    812 
    813    FT_FREE( loca_buf );
    814 
    815    return error;
    816  }
    817 
    818 
    819  static FT_Error
    820  reconstruct_glyf( FT_Stream    stream,
    821                    FT_ULong*    glyf_checksum,
    822                    FT_ULong*    loca_checksum,
    823                    FT_Byte**    sfnt_bytes,
    824                    FT_ULong*    sfnt_size,
    825                    FT_ULong*    out_offset,
    826                    WOFF2_Info   info,
    827                    FT_Memory    memory )
    828  {
    829    FT_Error  error = FT_Err_Ok;
    830    FT_Byte*  sfnt  = *sfnt_bytes;
    831 
    832    /* current position in stream */
    833    const FT_ULong  pos = FT_STREAM_POS();
    834 
    835    FT_UInt  num_substreams = 7;
    836 
    837    FT_UShort  option_flags;
    838    FT_UShort  num_glyphs;
    839    FT_UShort  index_format;
    840    FT_ULong   expected_loca_length;
    841    FT_UInt    offset;
    842    FT_UInt    i;
    843    FT_ULong   points_size;
    844    FT_ULong   glyph_buf_size;
    845    FT_ULong   bbox_bitmap_offset;
    846    FT_ULong   bbox_bitmap_length;
    847    FT_ULong   overlap_bitmap_offset = 0;
    848    FT_ULong   overlap_bitmap_length = 0;
    849 
    850    const FT_ULong  glyf_start  = *out_offset;
    851    FT_ULong        dest_offset = *out_offset;
    852 
    853    WOFF2_Substream  substreams = NULL;
    854 
    855    FT_ULong*    loca_values  = NULL;
    856    FT_UShort*   n_points_arr = NULL;
    857    FT_Byte*     glyph_buf    = NULL;
    858    WOFF2_Point  points       = NULL;
    859 
    860 
    861    if ( FT_QNEW_ARRAY( substreams, num_substreams ) )
    862      goto Fail;
    863 
    864    if ( FT_STREAM_SKIP( 2 ) )
    865      goto Fail;
    866    if ( FT_READ_USHORT( option_flags ) )
    867      goto Fail;
    868    if ( FT_READ_USHORT( num_glyphs ) )
    869      goto Fail;
    870    if ( FT_READ_USHORT( index_format ) )
    871      goto Fail;
    872 
    873    FT_TRACE4(( "option_flags = %u; num_glyphs = %u; index_format = %u\n",
    874                option_flags, num_glyphs, index_format ));
    875 
    876    info->num_glyphs = num_glyphs;
    877 
    878    /* Calculate expected length of loca and compare.          */
    879    /* See https://www.w3.org/TR/WOFF2/#conform-mustRejectLoca */
    880    /* index_format = 0 => Short version `loca'.               */
    881    /* index_format = 1 => Long version `loca'.                */
    882    expected_loca_length = ( index_format ? 4 : 2 ) *
    883                             ( (FT_ULong)num_glyphs + 1 );
    884    if ( info->loca_table->dst_length != expected_loca_length )
    885      goto Fail;
    886 
    887    offset = 2 + 2 + 2 + 2 + ( num_substreams * 4 );
    888    if ( offset > info->glyf_table->TransformLength )
    889      goto Fail;
    890 
    891    for ( i = 0; i < num_substreams; ++i )
    892    {
    893      FT_ULong  substream_size;
    894 
    895 
    896      if ( FT_READ_ULONG( substream_size ) )
    897        goto Fail;
    898      if ( substream_size > info->glyf_table->TransformLength - offset )
    899        goto Fail;
    900 
    901      substreams[i].start  = pos + offset;
    902      substreams[i].offset = pos + offset;
    903      substreams[i].size   = substream_size;
    904 
    905      FT_TRACE5(( "  Substream %u: offset = %lu; size = %lu;\n",
    906                  i, substreams[i].offset, substreams[i].size ));
    907      offset += substream_size;
    908    }
    909 
    910    if ( option_flags & HAVE_OVERLAP_SIMPLE_BITMAP )
    911    {
    912      /* Size of overlapBitmap = floor((numGlyphs + 7) / 8) */
    913      overlap_bitmap_length = ( num_glyphs + 7U ) >> 3;
    914      if ( overlap_bitmap_length > info->glyf_table->TransformLength - offset )
    915        goto Fail;
    916 
    917      overlap_bitmap_offset = pos + offset;
    918 
    919      FT_TRACE5(( "  Overlap bitmap: offset = %lu; size = %lu;\n",
    920                  overlap_bitmap_offset, overlap_bitmap_length ));
    921      offset += overlap_bitmap_length;
    922    }
    923 
    924    if ( FT_QNEW_ARRAY( loca_values, num_glyphs + 1 ) )
    925      goto Fail;
    926 
    927    points_size        = 0;
    928    bbox_bitmap_offset = substreams[BBOX_STREAM].offset;
    929 
    930    /* Size of bboxBitmap = 4 * floor((numGlyphs + 31) / 32) */
    931    bbox_bitmap_length              = ( ( num_glyphs + 31U ) >> 5 ) << 2;
    932    /* bboxStreamSize is the combined size of bboxBitmap and bboxStream. */
    933    substreams[BBOX_STREAM].offset += bbox_bitmap_length;
    934 
    935    glyph_buf_size = WOFF2_DEFAULT_GLYPH_BUF;
    936    if ( FT_QALLOC( glyph_buf, glyph_buf_size ) )
    937      goto Fail;
    938 
    939    if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) )
    940      goto Fail;
    941 
    942    for ( i = 0; i < num_glyphs; ++i )
    943    {
    944      FT_ULong   glyph_size = 0;
    945      FT_UShort  n_contours = 0;
    946      FT_Bool    have_bbox  = FALSE;
    947      FT_Byte    bbox_bitmap;
    948      FT_ULong   bbox_offset;
    949      FT_UShort  x_min      = 0;
    950 
    951 
    952      /* Set `have_bbox'. */
    953      bbox_offset = bbox_bitmap_offset + ( i >> 3 );
    954      if ( FT_STREAM_SEEK( bbox_offset ) ||
    955           FT_READ_BYTE( bbox_bitmap )   )
    956        goto Fail;
    957      if ( bbox_bitmap & ( 0x80 >> ( i & 7 ) ) )
    958        have_bbox = TRUE;
    959 
    960      /* Read value from `nContourStream'. */
    961      if ( FT_STREAM_SEEK( substreams[N_CONTOUR_STREAM].offset ) ||
    962           FT_READ_USHORT( n_contours )                          )
    963        goto Fail;
    964      substreams[N_CONTOUR_STREAM].offset += 2;
    965 
    966      if ( n_contours == 0xffff )
    967      {
    968        /* composite glyph */
    969        FT_Bool    have_instructions = FALSE;
    970        FT_UShort  instruction_size  = 0;
    971        FT_ULong   composite_size    = 0;
    972        FT_ULong   size_needed;
    973        FT_Byte*   pointer           = NULL;
    974 
    975 
    976        /* Composite glyphs must have explicit bbox. */
    977        if ( !have_bbox )
    978          goto Fail;
    979 
    980        if ( compositeGlyph_size( stream,
    981                                  substreams[COMPOSITE_STREAM].offset,
    982                                  &composite_size,
    983                                  &have_instructions) )
    984          goto Fail;
    985 
    986        if ( have_instructions )
    987        {
    988          if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) ||
    989               READ_255USHORT( instruction_size )                )
    990            goto Fail;
    991          substreams[GLYPH_STREAM].offset = FT_STREAM_POS();
    992        }
    993 
    994        size_needed = 12 + composite_size + instruction_size;
    995        if ( glyph_buf_size < size_needed )
    996        {
    997          if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) )
    998            goto Fail;
    999          glyph_buf_size = size_needed;
   1000        }
   1001 
   1002        pointer = glyph_buf + glyph_size;
   1003        WRITE_USHORT( pointer, n_contours );
   1004        glyph_size += 2;
   1005 
   1006        /* Read x_min for current glyph. */
   1007        if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) ||
   1008             FT_READ_USHORT( x_min )                          )
   1009          goto Fail;
   1010        /* No increment here because we read again. */
   1011 
   1012        if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) ||
   1013             FT_STREAM_READ( glyph_buf + glyph_size, 8 )      )
   1014          goto Fail;
   1015 
   1016        substreams[BBOX_STREAM].offset += 8;
   1017        glyph_size                     += 8;
   1018 
   1019        if ( FT_STREAM_SEEK( substreams[COMPOSITE_STREAM].offset )    ||
   1020             FT_STREAM_READ( glyph_buf + glyph_size, composite_size ) )
   1021          goto Fail;
   1022 
   1023        substreams[COMPOSITE_STREAM].offset += composite_size;
   1024        glyph_size                          += composite_size;
   1025 
   1026        if ( have_instructions )
   1027        {
   1028          pointer = glyph_buf + glyph_size;
   1029          WRITE_USHORT( pointer, instruction_size );
   1030          glyph_size += 2;
   1031 
   1032          if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset )    ||
   1033               FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) )
   1034            goto Fail;
   1035 
   1036          substreams[INSTRUCTION_STREAM].offset += instruction_size;
   1037          glyph_size                            += instruction_size;
   1038        }
   1039      }
   1040      else if ( n_contours > 0 )
   1041      {
   1042        /* simple glyph */
   1043        FT_ULong   total_n_points = 0;
   1044        FT_UShort  n_points_contour;
   1045        FT_UInt    j;
   1046        FT_ULong   flag_size;
   1047        FT_ULong   triplet_size;
   1048        FT_ULong   triplet_bytes_used;
   1049        FT_Bool    have_overlap  = FALSE;
   1050        FT_Byte    overlap_bitmap;
   1051        FT_ULong   overlap_offset;
   1052        FT_Byte*   flags_buf     = NULL;
   1053        FT_Byte*   triplet_buf   = NULL;
   1054        FT_UShort  instruction_size;
   1055        FT_ULong   size_needed;
   1056        FT_Int     end_point;
   1057        FT_UInt    contour_ix;
   1058 
   1059        FT_Byte*   pointer = NULL;
   1060 
   1061 
   1062        /* Set `have_overlap`. */
   1063        if ( overlap_bitmap_offset )
   1064        {
   1065          overlap_offset = overlap_bitmap_offset + ( i >> 3 );
   1066          if ( FT_STREAM_SEEK( overlap_offset ) ||
   1067               FT_READ_BYTE( overlap_bitmap )   )
   1068            goto Fail;
   1069          if ( overlap_bitmap & ( 0x80 >> ( i & 7 ) ) )
   1070            have_overlap = TRUE;
   1071        }
   1072 
   1073        if ( FT_QNEW_ARRAY( n_points_arr, n_contours ) )
   1074          goto Fail;
   1075 
   1076        if ( FT_STREAM_SEEK( substreams[N_POINTS_STREAM].offset ) )
   1077          goto Fail;
   1078 
   1079        for ( j = 0; j < n_contours; ++j )
   1080        {
   1081          if ( READ_255USHORT( n_points_contour ) )
   1082            goto Fail;
   1083          n_points_arr[j] = n_points_contour;
   1084          /* Prevent negative/overflow. */
   1085          if ( total_n_points + n_points_contour < total_n_points )
   1086            goto Fail;
   1087          total_n_points += n_points_contour;
   1088        }
   1089        substreams[N_POINTS_STREAM].offset = FT_STREAM_POS();
   1090 
   1091        flag_size = total_n_points;
   1092        if ( flag_size > substreams[FLAG_STREAM].size )
   1093          goto Fail;
   1094 
   1095        flags_buf   = stream->base + substreams[FLAG_STREAM].offset;
   1096        triplet_buf = stream->base + substreams[GLYPH_STREAM].offset;
   1097 
   1098        if ( substreams[GLYPH_STREAM].size <
   1099               ( substreams[GLYPH_STREAM].offset -
   1100                 substreams[GLYPH_STREAM].start ) )
   1101          goto Fail;
   1102 
   1103        triplet_size       = substreams[GLYPH_STREAM].size -
   1104                               ( substreams[GLYPH_STREAM].offset -
   1105                                 substreams[GLYPH_STREAM].start );
   1106        triplet_bytes_used = 0;
   1107 
   1108        /* Create array to store point information. */
   1109        points_size = total_n_points;
   1110        if ( FT_QNEW_ARRAY( points, points_size ) )
   1111          goto Fail;
   1112 
   1113        if ( triplet_decode( flags_buf,
   1114                             triplet_buf,
   1115                             triplet_size,
   1116                             total_n_points,
   1117                             points,
   1118                             &triplet_bytes_used ) )
   1119          goto Fail;
   1120 
   1121        substreams[FLAG_STREAM].offset  += flag_size;
   1122        substreams[GLYPH_STREAM].offset += triplet_bytes_used;
   1123 
   1124        if ( FT_STREAM_SEEK( substreams[GLYPH_STREAM].offset ) ||
   1125             READ_255USHORT( instruction_size )                )
   1126          goto Fail;
   1127 
   1128        substreams[GLYPH_STREAM].offset = FT_STREAM_POS();
   1129 
   1130        if ( total_n_points >= ( 1 << 27 ) )
   1131          goto Fail;
   1132 
   1133        size_needed = 12 +
   1134                      ( 2 * n_contours ) +
   1135                      ( 5 * total_n_points ) +
   1136                      instruction_size;
   1137        if ( glyph_buf_size < size_needed )
   1138        {
   1139          if ( FT_QREALLOC( glyph_buf, glyph_buf_size, size_needed ) )
   1140            goto Fail;
   1141          glyph_buf_size = size_needed;
   1142        }
   1143 
   1144        pointer = glyph_buf + glyph_size;
   1145        WRITE_USHORT( pointer, n_contours );
   1146        glyph_size += 2;
   1147 
   1148        if ( have_bbox )
   1149        {
   1150          /* Read x_min for current glyph. */
   1151          if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) ||
   1152               FT_READ_USHORT( x_min )                          )
   1153            goto Fail;
   1154          /* No increment here because we read again. */
   1155 
   1156          if ( FT_STREAM_SEEK( substreams[BBOX_STREAM].offset ) ||
   1157               FT_STREAM_READ( glyph_buf + glyph_size, 8 )      )
   1158            goto Fail;
   1159          substreams[BBOX_STREAM].offset += 8;
   1160        }
   1161        else
   1162          compute_bbox( total_n_points, points, glyph_buf, &x_min );
   1163 
   1164        glyph_size = CONTOUR_OFFSET_END_POINT;
   1165 
   1166        pointer   = glyph_buf + glyph_size;
   1167        end_point = -1;
   1168 
   1169        for ( contour_ix = 0; contour_ix < n_contours; ++contour_ix )
   1170        {
   1171          end_point += n_points_arr[contour_ix];
   1172          if ( end_point >= 65536 )
   1173            goto Fail;
   1174 
   1175          WRITE_SHORT( pointer, end_point );
   1176          glyph_size += 2;
   1177        }
   1178 
   1179        WRITE_USHORT( pointer, instruction_size );
   1180        glyph_size += 2;
   1181 
   1182        if ( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset )    ||
   1183             FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) )
   1184          goto Fail;
   1185 
   1186        substreams[INSTRUCTION_STREAM].offset += instruction_size;
   1187        glyph_size                            += instruction_size;
   1188 
   1189        if ( store_points( total_n_points,
   1190                           points,
   1191                           n_contours,
   1192                           instruction_size,
   1193                           have_overlap,
   1194                           glyph_buf,
   1195                           glyph_buf_size,
   1196                           &glyph_size ) )
   1197          goto Fail;
   1198 
   1199        FT_FREE( points );
   1200        FT_FREE( n_points_arr );
   1201      }
   1202      else
   1203      {
   1204        /* Empty glyph.          */
   1205        /* Must not have a bbox. */
   1206        if ( have_bbox )
   1207        {
   1208          FT_ERROR(( "Empty glyph has a bbox.\n" ));
   1209          goto Fail;
   1210        }
   1211      }
   1212 
   1213      loca_values[i] = dest_offset - glyf_start;
   1214 
   1215      if ( WRITE_SFNT_BUF( glyph_buf, glyph_size ) )
   1216        goto Fail;
   1217 
   1218      if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) )
   1219        goto Fail;
   1220 
   1221      *glyf_checksum += compute_ULong_sum( glyph_buf, glyph_size );
   1222 
   1223      /* Store x_mins, may be required to reconstruct `hmtx'. */
   1224      info->x_mins[i] = (FT_Short)x_min;
   1225    }
   1226 
   1227    info->glyf_table->dst_length = dest_offset - info->glyf_table->dst_offset;
   1228    info->loca_table->dst_offset = dest_offset;
   1229 
   1230    /* `loca[n]' will be equal to the length of the `glyf' table. */
   1231    loca_values[num_glyphs] = info->glyf_table->dst_length;
   1232 
   1233    if ( store_loca( loca_values,
   1234                     num_glyphs + 1,
   1235                     index_format,
   1236                     loca_checksum,
   1237                     &sfnt,
   1238                     sfnt_size,
   1239                     &dest_offset,
   1240                     memory ) )
   1241      goto Fail;
   1242 
   1243    info->loca_table->dst_length = dest_offset - info->loca_table->dst_offset;
   1244 
   1245    FT_TRACE4(( "  loca table info:\n" ));
   1246    FT_TRACE4(( "    dst_offset = %lu\n", info->loca_table->dst_offset ));
   1247    FT_TRACE4(( "    dst_length = %lu\n", info->loca_table->dst_length ));
   1248    FT_TRACE4(( "    checksum = %09lx\n", *loca_checksum ));
   1249 
   1250    /* Set pointer `sfnt_bytes' to its correct value. */
   1251    *sfnt_bytes = sfnt;
   1252    *out_offset = dest_offset;
   1253 
   1254    FT_FREE( substreams );
   1255    FT_FREE( loca_values );
   1256    FT_FREE( n_points_arr );
   1257    FT_FREE( glyph_buf );
   1258    FT_FREE( points );
   1259 
   1260    return error;
   1261 
   1262  Fail:
   1263    if ( !error )
   1264      error = FT_THROW( Invalid_Table );
   1265 
   1266    /* Set pointer `sfnt_bytes' to its correct value. */
   1267    *sfnt_bytes = sfnt;
   1268 
   1269    FT_FREE( substreams );
   1270    FT_FREE( loca_values );
   1271    FT_FREE( n_points_arr );
   1272    FT_FREE( glyph_buf );
   1273    FT_FREE( points );
   1274 
   1275    return error;
   1276  }
   1277 
   1278 
   1279  /* Get `x_mins' for untransformed `glyf' table. */
   1280  static FT_Error
   1281  get_x_mins( FT_Stream     stream,
   1282              WOFF2_Table*  tables,
   1283              FT_UShort     num_tables,
   1284              WOFF2_Info    info,
   1285              FT_Memory     memory )
   1286  {
   1287    FT_UShort  num_glyphs;
   1288    FT_UShort  index_format;
   1289    FT_ULong   glyf_offset;
   1290    FT_UShort  glyf_offset_short;
   1291    FT_ULong   loca_offset;
   1292    FT_Int     i;
   1293    FT_Error   error = FT_Err_Ok;
   1294    FT_ULong   offset_size;
   1295 
   1296    /* At this point of time those tables might not have been read yet. */
   1297    const WOFF2_Table  maxp_table = find_table( tables, num_tables,
   1298                                                TTAG_maxp );
   1299    const WOFF2_Table  head_table = find_table( tables, num_tables,
   1300                                                TTAG_head );
   1301 
   1302 
   1303    if ( !maxp_table )
   1304    {
   1305      FT_ERROR(( "`maxp' table is missing.\n" ));
   1306      return FT_THROW( Invalid_Table );
   1307    }
   1308 
   1309    if ( !head_table )
   1310    {
   1311      FT_ERROR(( "`head' table is missing.\n" ));
   1312      return FT_THROW( Invalid_Table );
   1313    }
   1314 
   1315    if ( !info->loca_table )
   1316    {
   1317      FT_ERROR(( "`loca' table is missing.\n" ));
   1318      return FT_THROW( Invalid_Table );
   1319    }
   1320 
   1321    /* Read `numGlyphs' field from `maxp' table. */
   1322    if ( FT_STREAM_SEEK( maxp_table->src_offset ) || FT_STREAM_SKIP( 8 ) )
   1323      return error;
   1324 
   1325    if ( FT_READ_USHORT( num_glyphs ) )
   1326      return error;
   1327 
   1328    info->num_glyphs = num_glyphs;
   1329 
   1330    /* Read `indexToLocFormat' field from `head' table. */
   1331    if ( FT_STREAM_SEEK( head_table->src_offset ) ||
   1332         FT_STREAM_SKIP( 50 )                     )
   1333      return error;
   1334 
   1335    if ( FT_READ_USHORT( index_format ) )
   1336      return error;
   1337 
   1338    offset_size = index_format ? 4 : 2;
   1339 
   1340    /* Create `x_mins' array. */
   1341    if ( FT_QNEW_ARRAY( info->x_mins, num_glyphs ) )
   1342      return error;
   1343 
   1344    loca_offset = info->loca_table->src_offset;
   1345 
   1346    for ( i = 0; i < num_glyphs; ++i )
   1347    {
   1348      if ( FT_STREAM_SEEK( loca_offset ) )
   1349        return error;
   1350 
   1351      loca_offset += offset_size;
   1352 
   1353      if ( index_format )
   1354      {
   1355        if ( FT_READ_ULONG( glyf_offset ) )
   1356          return error;
   1357      }
   1358      else
   1359      {
   1360        if ( FT_READ_USHORT( glyf_offset_short ) )
   1361          return error;
   1362 
   1363        glyf_offset = (FT_ULong)( glyf_offset_short );
   1364        glyf_offset = glyf_offset << 1;
   1365      }
   1366 
   1367      glyf_offset += info->glyf_table->src_offset;
   1368 
   1369      if ( FT_STREAM_SEEK( glyf_offset ) || FT_STREAM_SKIP( 2 ) )
   1370        return error;
   1371 
   1372      if ( FT_READ_SHORT( info->x_mins[i] ) )
   1373        return error;
   1374    }
   1375 
   1376    return error;
   1377  }
   1378 
   1379 
   1380  static FT_Error
   1381  reconstruct_hmtx( FT_Stream  stream,
   1382                    FT_UShort  num_glyphs,
   1383                    FT_UShort  num_hmetrics,
   1384                    FT_Short*  x_mins,
   1385                    FT_ULong*  checksum,
   1386                    FT_Byte**  sfnt_bytes,
   1387                    FT_ULong*  sfnt_size,
   1388                    FT_ULong*  out_offset,
   1389                    FT_Memory  memory )
   1390  {
   1391    FT_Error  error       = FT_Err_Ok;
   1392    FT_Byte*  sfnt        = *sfnt_bytes;
   1393    FT_ULong  dest_offset = *out_offset;
   1394 
   1395    FT_Byte   hmtx_flags;
   1396    FT_Bool   has_proportional_lsbs, has_monospace_lsbs;
   1397    FT_ULong  hmtx_table_size;
   1398    FT_Int    i;
   1399 
   1400    FT_UShort*  advance_widths = NULL;
   1401    FT_Short*   lsbs           = NULL;
   1402    FT_Byte*    hmtx_table     = NULL;
   1403    FT_Byte*    dst            = NULL;
   1404 
   1405 
   1406    if ( FT_READ_BYTE( hmtx_flags ) )
   1407      goto Fail;
   1408 
   1409    has_proportional_lsbs = ( hmtx_flags & 1 ) == 0;
   1410    has_monospace_lsbs    = ( hmtx_flags & 2 ) == 0;
   1411 
   1412    /* Bits 2-7 are reserved and MUST be zero. */
   1413    if ( ( hmtx_flags & 0xFC ) != 0 )
   1414      goto Fail;
   1415 
   1416    /* Are you REALLY transformed? */
   1417    if ( has_proportional_lsbs && has_monospace_lsbs )
   1418      goto Fail;
   1419 
   1420    /* Cannot have a transformed `hmtx' without `glyf'. */
   1421    if ( ( num_hmetrics > num_glyphs ) ||
   1422         ( num_hmetrics < 1 )          )
   1423      goto Fail;
   1424 
   1425    /* Must have at least one entry. */
   1426    if ( num_hmetrics < 1 )
   1427      goto Fail;
   1428 
   1429    if ( FT_QNEW_ARRAY( advance_widths, num_hmetrics ) ||
   1430         FT_QNEW_ARRAY( lsbs, num_glyphs )             )
   1431      goto Fail;
   1432 
   1433    /* Read `advanceWidth' stream.  Always present. */
   1434    for ( i = 0; i < num_hmetrics; i++ )
   1435    {
   1436      FT_UShort  advance_width;
   1437 
   1438 
   1439      if ( FT_READ_USHORT( advance_width ) )
   1440        goto Fail;
   1441 
   1442      advance_widths[i] = advance_width;
   1443    }
   1444 
   1445    /* lsb values for proportional glyphs. */
   1446    for ( i = 0; i < num_hmetrics; i++ )
   1447    {
   1448      FT_Short  lsb;
   1449 
   1450 
   1451      if ( has_proportional_lsbs )
   1452      {
   1453        if ( FT_READ_SHORT( lsb ) )
   1454          goto Fail;
   1455      }
   1456      else
   1457        lsb = x_mins[i];
   1458 
   1459      lsbs[i] = lsb;
   1460    }
   1461 
   1462    /* lsb values for monospaced glyphs. */
   1463    for ( i = num_hmetrics; i < num_glyphs; i++ )
   1464    {
   1465      FT_Short  lsb;
   1466 
   1467 
   1468      if ( has_monospace_lsbs )
   1469      {
   1470        if ( FT_READ_SHORT( lsb ) )
   1471          goto Fail;
   1472      }
   1473      else
   1474        lsb = x_mins[i];
   1475 
   1476      lsbs[i] = lsb;
   1477    }
   1478 
   1479    /* Build the hmtx table. */
   1480    hmtx_table_size = 2 * num_hmetrics + 2 * num_glyphs;
   1481    if ( FT_QALLOC( hmtx_table, hmtx_table_size ) )
   1482      goto Fail;
   1483 
   1484    dst = hmtx_table;
   1485    FT_TRACE6(( "hmtx values: \n" ));
   1486    for ( i = 0; i < num_glyphs; i++ )
   1487    {
   1488      if ( i < num_hmetrics )
   1489      {
   1490        WRITE_SHORT( dst, advance_widths[i] );
   1491        FT_TRACE6(( "%d ", advance_widths[i] ));
   1492      }
   1493 
   1494      WRITE_SHORT( dst, lsbs[i] );
   1495      FT_TRACE6(( "%d ", lsbs[i] ));
   1496    }
   1497    FT_TRACE6(( "\n" ));
   1498 
   1499    *checksum = compute_ULong_sum( hmtx_table, hmtx_table_size );
   1500    /* Write `hmtx' table to sfnt buffer. */
   1501    if ( WRITE_SFNT_BUF( hmtx_table, hmtx_table_size ) )
   1502      goto Fail;
   1503 
   1504    /* Set pointer `sfnt_bytes' to its correct value. */
   1505    *sfnt_bytes = sfnt;
   1506    *out_offset = dest_offset;
   1507 
   1508    FT_FREE( advance_widths );
   1509    FT_FREE( lsbs );
   1510    FT_FREE( hmtx_table );
   1511 
   1512    return error;
   1513 
   1514  Fail:
   1515    FT_FREE( advance_widths );
   1516    FT_FREE( lsbs );
   1517    FT_FREE( hmtx_table );
   1518 
   1519    if ( !error )
   1520      error = FT_THROW( Invalid_Table );
   1521 
   1522    return error;
   1523  }
   1524 
   1525 
   1526  static FT_Error
   1527  reconstruct_font( FT_Byte*      transformed_buf,
   1528                    FT_ULong      transformed_buf_size,
   1529                    WOFF2_Table*  indices,
   1530                    WOFF2_Header  woff2,
   1531                    WOFF2_Info    info,
   1532                    FT_Byte**     sfnt_bytes,
   1533                    FT_ULong*     sfnt_size,
   1534                    FT_Memory     memory )
   1535  {
   1536    /* Memory management of `transformed_buf' is handled by the caller. */
   1537 
   1538    FT_Error   error      = FT_Err_Ok;
   1539    FT_Stream  stream     = NULL;
   1540    FT_Byte*   buf_cursor = NULL;
   1541    FT_Byte    table_entry[16];
   1542 
   1543    /* We are reallocating memory for `sfnt', so its pointer may change. */
   1544    FT_Byte*   sfnt = *sfnt_bytes;
   1545 
   1546    FT_UShort  num_tables  = woff2->num_tables;
   1547    FT_ULong   dest_offset = 12 + num_tables * 16UL;
   1548 
   1549    FT_ULong   checksum      = 0;
   1550    FT_ULong   loca_checksum = 0;
   1551    FT_Int     nn            = 0;
   1552    FT_UShort  num_hmetrics  = 0;
   1553    FT_ULong   font_checksum = info->header_checksum;
   1554    FT_Bool    is_glyf_xform = FALSE;
   1555 
   1556    FT_ULong  table_entry_offset = 12;
   1557 
   1558 
   1559    /* A few table checks before reconstruction. */
   1560    /* `glyf' must be present with `loca'.       */
   1561    info->glyf_table = find_table( indices, num_tables, TTAG_glyf );
   1562    info->loca_table = find_table( indices, num_tables, TTAG_loca );
   1563 
   1564    if ( ( info->glyf_table == NULL ) ^ ( info->loca_table == NULL ) )
   1565    {
   1566      FT_ERROR(( "One of `glyf'/`loca' tables missing.\n" ));
   1567      return FT_THROW( Invalid_Table );
   1568    }
   1569 
   1570    /* Both `glyf' and `loca' must have same transformation. */
   1571    if ( info->glyf_table != NULL )
   1572    {
   1573      if ( ( info->glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) !=
   1574           ( info->loca_table->flags & WOFF2_FLAGS_TRANSFORM ) )
   1575      {
   1576        FT_ERROR(( "Transformation mismatch"
   1577                   " between `glyf' and `loca' table." ));
   1578        return FT_THROW( Invalid_Table );
   1579      }
   1580    }
   1581 
   1582    /* Create a stream for the uncompressed buffer. */
   1583    if ( FT_NEW( stream ) )
   1584      goto Fail;
   1585    FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size );
   1586 
   1587    FT_ASSERT( FT_STREAM_POS() == 0 );
   1588 
   1589    /* Reconstruct/copy tables to output stream. */
   1590    for ( nn = 0; nn < num_tables; nn++ )
   1591    {
   1592      WOFF2_TableRec  table = *( indices[nn] );
   1593 
   1594 
   1595      FT_TRACE3(( "Seeking to %lu with table size %lu.\n",
   1596                  table.src_offset, table.src_length ));
   1597      FT_TRACE3(( "Table tag: %c%c%c%c.\n",
   1598                  (FT_Char)( table.Tag >> 24 ),
   1599                  (FT_Char)( table.Tag >> 16 ),
   1600                  (FT_Char)( table.Tag >> 8  ),
   1601                  (FT_Char)( table.Tag       ) ));
   1602 
   1603      if ( FT_STREAM_SEEK( table.src_offset ) )
   1604        goto Fail;
   1605 
   1606      if ( table.src_offset + table.src_length > transformed_buf_size )
   1607        goto Fail;
   1608 
   1609      /* Get stream size for fields of `hmtx' table. */
   1610      if ( table.Tag == TTAG_hhea )
   1611      {
   1612        if ( read_num_hmetrics( stream, &num_hmetrics ) )
   1613          goto Fail;
   1614      }
   1615 
   1616      info->num_hmetrics = num_hmetrics;
   1617 
   1618      checksum = 0;
   1619      if ( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM )
   1620      {
   1621        /* Check whether `head' is at least 12 bytes. */
   1622        if ( table.Tag == TTAG_head )
   1623        {
   1624          if ( table.src_length < 12 )
   1625            goto Fail;
   1626 
   1627          buf_cursor = transformed_buf + table.src_offset + 8;
   1628          /* Set checkSumAdjustment = 0 */
   1629          WRITE_ULONG( buf_cursor, 0 );
   1630        }
   1631 
   1632        table.dst_offset = dest_offset;
   1633 
   1634        checksum = compute_ULong_sum( transformed_buf + table.src_offset,
   1635                                      table.src_length );
   1636        FT_TRACE4(( "Checksum = %09lx.\n", checksum ));
   1637 
   1638        if ( WRITE_SFNT_BUF( transformed_buf + table.src_offset,
   1639                             table.src_length ) )
   1640          goto Fail;
   1641      }
   1642      else
   1643      {
   1644        FT_TRACE3(( "This table is transformed.\n" ));
   1645 
   1646        if ( table.Tag == TTAG_glyf )
   1647        {
   1648          is_glyf_xform    = TRUE;
   1649          table.dst_offset = dest_offset;
   1650 
   1651          if ( reconstruct_glyf( stream,
   1652                                 &checksum,
   1653                                 &loca_checksum,
   1654                                 &sfnt,
   1655                                 sfnt_size,
   1656                                 &dest_offset,
   1657                                 info,
   1658                                 memory ) )
   1659            goto Fail;
   1660 
   1661          FT_TRACE4(( "Checksum = %09lx.\n", checksum ));
   1662        }
   1663 
   1664        else if ( table.Tag == TTAG_loca )
   1665          checksum = loca_checksum;
   1666 
   1667        else if ( table.Tag == TTAG_hmtx )
   1668        {
   1669          /* If glyf is not transformed and hmtx is, handle separately. */
   1670          if ( !is_glyf_xform )
   1671          {
   1672            if ( get_x_mins( stream, indices, num_tables, info, memory ) )
   1673              goto Fail;
   1674          }
   1675 
   1676          table.dst_offset = dest_offset;
   1677 
   1678          if ( reconstruct_hmtx( stream,
   1679                                 info->num_glyphs,
   1680                                 info->num_hmetrics,
   1681                                 info->x_mins,
   1682                                 &checksum,
   1683                                 &sfnt,
   1684                                 sfnt_size,
   1685                                 &dest_offset,
   1686                                 memory ) )
   1687            goto Fail;
   1688        }
   1689        else
   1690        {
   1691          /* Unknown transform. */
   1692          FT_ERROR(( "Unknown table transform.\n" ));
   1693          goto Fail;
   1694        }
   1695      }
   1696 
   1697      font_checksum += checksum;
   1698 
   1699      buf_cursor = &table_entry[0];
   1700      WRITE_ULONG( buf_cursor, table.Tag );
   1701      WRITE_ULONG( buf_cursor, checksum );
   1702      WRITE_ULONG( buf_cursor, table.dst_offset );
   1703      WRITE_ULONG( buf_cursor, table.dst_length );
   1704 
   1705      WRITE_SFNT_BUF_AT( table_entry_offset, table_entry, 16 );
   1706 
   1707      /* Update checksum. */
   1708      font_checksum += compute_ULong_sum( table_entry, 16 );
   1709 
   1710      if ( pad4( &sfnt, sfnt_size, &dest_offset, memory ) )
   1711        goto Fail;
   1712 
   1713      /* Sanity check. */
   1714      if ( (FT_ULong)( table.dst_offset + table.dst_length ) > dest_offset )
   1715      {
   1716        FT_ERROR(( "Table was partially written.\n" ));
   1717        goto Fail;
   1718      }
   1719    }
   1720 
   1721    /* Update `head' checkSumAdjustment. */
   1722    info->head_table = find_table( indices, num_tables, TTAG_head );
   1723    if ( !info->head_table )
   1724    {
   1725      FT_ERROR(( "`head' table is missing.\n" ));
   1726      goto Fail;
   1727    }
   1728 
   1729    if ( info->head_table->dst_length < 12 )
   1730      goto Fail;
   1731 
   1732    buf_cursor    = sfnt + info->head_table->dst_offset + 8;
   1733    font_checksum = 0xB1B0AFBA - font_checksum;
   1734 
   1735    WRITE_ULONG( buf_cursor, font_checksum );
   1736 
   1737    FT_TRACE2(( "Final checksum = %09lx.\n", font_checksum ));
   1738 
   1739    woff2->actual_sfnt_size = dest_offset;
   1740 
   1741    /* Set pointer of sfnt stream to its correct value. */
   1742    *sfnt_bytes = sfnt;
   1743 
   1744    FT_Stream_Close( stream );
   1745    FT_FREE( stream );
   1746 
   1747    return error;
   1748 
   1749  Fail:
   1750    if ( !error )
   1751      error = FT_THROW( Invalid_Table );
   1752 
   1753    /* Set pointer of sfnt stream to its correct value. */
   1754    *sfnt_bytes = sfnt;
   1755 
   1756    FT_Stream_Close( stream );
   1757    FT_FREE( stream );
   1758 
   1759    return error;
   1760  }
   1761 
   1762 
   1763  /* Replace `face->root.stream' with a stream containing the extracted */
   1764  /* SFNT of a WOFF2 font.                                              */
   1765 
   1766  FT_LOCAL_DEF( FT_Error )
   1767  woff2_open_font( FT_Stream  stream,
   1768                   TT_Face    face,
   1769                   FT_Int*    face_instance_index,
   1770                   FT_Long*   num_faces )
   1771  {
   1772    FT_Memory  memory = stream->memory;
   1773    FT_Error   error  = FT_Err_Ok;
   1774    FT_Int     face_index;
   1775 
   1776    WOFF2_HeaderRec  woff2;
   1777    WOFF2_InfoRec    info         = { 0, 0, 0, NULL, NULL, NULL, NULL };
   1778    WOFF2_Table      tables       = NULL;
   1779    WOFF2_Table*     indices      = NULL;
   1780    WOFF2_Table*     temp_indices = NULL;
   1781    WOFF2_Table      last_table;
   1782 
   1783    FT_Int     nn;
   1784    FT_ULong   j;
   1785    FT_ULong   flags;
   1786    FT_UShort  xform_version;
   1787    FT_ULong   src_offset = 0;
   1788 
   1789    FT_UInt    glyf_index;
   1790    FT_UInt    loca_index;
   1791    FT_UInt32  file_offset;
   1792 
   1793    FT_Byte*   sfnt        = NULL;
   1794    FT_Stream  sfnt_stream = NULL;
   1795    FT_ULong   sfnt_size;
   1796 
   1797    FT_Byte*  uncompressed_buf = NULL;
   1798 
   1799    static const FT_Frame_Field  woff2_header_fields[] =
   1800    {
   1801 #undef  FT_STRUCTURE
   1802 #define FT_STRUCTURE  WOFF2_HeaderRec
   1803 
   1804      FT_FRAME_START( 48 ),
   1805        FT_FRAME_ULONG     ( signature ),
   1806        FT_FRAME_ULONG     ( flavor ),
   1807        FT_FRAME_ULONG     ( length ),
   1808        FT_FRAME_USHORT    ( num_tables ),
   1809        FT_FRAME_SKIP_BYTES( 2 ),
   1810        FT_FRAME_ULONG     ( totalSfntSize ),
   1811        FT_FRAME_ULONG     ( totalCompressedSize ),
   1812        FT_FRAME_SKIP_BYTES( 2 * 2 ),
   1813        FT_FRAME_ULONG     ( metaOffset ),
   1814        FT_FRAME_ULONG     ( metaLength ),
   1815        FT_FRAME_ULONG     ( metaOrigLength ),
   1816        FT_FRAME_ULONG     ( privOffset ),
   1817        FT_FRAME_ULONG     ( privLength ),
   1818      FT_FRAME_END
   1819    };
   1820 
   1821 
   1822    FT_ASSERT( stream == face->root.stream );
   1823    FT_ASSERT( FT_STREAM_POS() == 0 );
   1824 
   1825    face_index = FT_ABS( *face_instance_index ) & 0xFFFF;
   1826 
   1827    /* Read WOFF2 Header. */
   1828    if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) )
   1829      return error;
   1830 
   1831    FT_TRACE4(( "signature     -> 0x%lX\n", woff2.signature ));
   1832    FT_TRACE2(( "flavor        -> 0x%08lx\n", woff2.flavor ));
   1833    FT_TRACE4(( "length        -> %lu\n", woff2.length ));
   1834    FT_TRACE2(( "num_tables    -> %hu\n", woff2.num_tables ));
   1835    FT_TRACE4(( "totalSfntSize -> %lu\n", woff2.totalSfntSize ));
   1836    FT_TRACE4(( "metaOffset    -> %lu\n", woff2.metaOffset ));
   1837    FT_TRACE4(( "metaLength    -> %lu\n", woff2.metaLength ));
   1838    FT_TRACE4(( "privOffset    -> %lu\n", woff2.privOffset ));
   1839    FT_TRACE4(( "privLength    -> %lu\n", woff2.privLength ));
   1840 
   1841    /* Make sure we don't recurse back here. */
   1842    if ( woff2.flavor == TTAG_wOF2 )
   1843      return FT_THROW( Invalid_Table );
   1844 
   1845    /* Miscellaneous checks. */
   1846    if ( woff2.length != stream->size                               ||
   1847         woff2.num_tables == 0                                      ||
   1848         woff2.num_tables >  0xFFFU                                 ||
   1849         48 + woff2.num_tables * 20UL >= woff2.length               ||
   1850         ( woff2.metaOffset == 0 && ( woff2.metaLength != 0     ||
   1851                                      woff2.metaOrigLength != 0 ) ) ||
   1852         ( woff2.metaLength != 0 && woff2.metaOrigLength == 0 )     ||
   1853         ( woff2.metaOffset >= woff2.length )                       ||
   1854         ( woff2.length - woff2.metaOffset < woff2.metaLength )     ||
   1855         ( woff2.privOffset == 0 && woff2.privLength != 0 )         ||
   1856         ( woff2.privOffset >= woff2.length )                       ||
   1857         ( woff2.length - woff2.privOffset < woff2.privLength )     )
   1858    {
   1859      FT_ERROR(( "woff2_open_font: invalid WOFF2 header\n" ));
   1860      return FT_THROW( Invalid_Table );
   1861    }
   1862 
   1863    FT_TRACE2(( "woff2_open_font: WOFF2 Header is valid.\n" ));
   1864 
   1865    woff2.ttc_fonts = NULL;
   1866 
   1867    /* Read table directory. */
   1868    if ( FT_QNEW_ARRAY( tables, woff2.num_tables )  ||
   1869         FT_QNEW_ARRAY( indices, woff2.num_tables ) )
   1870      goto Exit;
   1871 
   1872    FT_TRACE2(( "\n" ));
   1873    FT_TRACE2(( "  tag    flags    transform  origLen   transformLen   offset\n" ));
   1874    FT_TRACE2(( "  -----------------------------------------------------------\n" ));
   1875             /* "  XXXX  XXXXXXXX  XXXXXXXX   XXXXXXXX    XXXXXXXX    XXXXXXXX" */
   1876 
   1877    for ( nn = 0; nn < woff2.num_tables; nn++ )
   1878    {
   1879      WOFF2_Table  table = tables + nn;
   1880 
   1881 
   1882      if ( FT_READ_BYTE( table->FlagByte ) )
   1883        goto Exit;
   1884 
   1885      if ( ( table->FlagByte & 0x3f ) == 0x3f )
   1886      {
   1887        if ( FT_READ_ULONG( table->Tag ) )
   1888          goto Exit;
   1889      }
   1890      else
   1891      {
   1892        table->Tag = woff2_known_tags( table->FlagByte & 0x3f );
   1893        if ( !table->Tag )
   1894        {
   1895          FT_ERROR(( "woff2_open_font: Unknown table tag." ));
   1896          error = FT_THROW( Invalid_Table );
   1897          goto Exit;
   1898        }
   1899      }
   1900 
   1901      flags = 0;
   1902      xform_version = ( table->FlagByte >> 6 ) & 0x03;
   1903 
   1904      /* 0 means xform for glyph/loca, non-0 for others. */
   1905      if ( table->Tag == TTAG_glyf || table->Tag == TTAG_loca )
   1906      {
   1907        if ( xform_version == 0 )
   1908          flags |= WOFF2_FLAGS_TRANSFORM;
   1909      }
   1910      else if ( xform_version != 0 )
   1911        flags |= WOFF2_FLAGS_TRANSFORM;
   1912 
   1913      flags |= xform_version;
   1914 
   1915      if ( READ_BASE128( table->dst_length ) )
   1916        goto Exit;
   1917 
   1918      table->TransformLength = table->dst_length;
   1919 
   1920      if ( ( flags & WOFF2_FLAGS_TRANSFORM ) != 0 )
   1921      {
   1922        if ( READ_BASE128( table->TransformLength ) )
   1923          goto Exit;
   1924 
   1925        if ( table->Tag == TTAG_loca && table->TransformLength )
   1926        {
   1927          FT_ERROR(( "woff2_open_font: Invalid loca `transformLength'.\n" ));
   1928          error = FT_THROW( Invalid_Table );
   1929          goto Exit;
   1930        }
   1931      }
   1932 
   1933      if ( src_offset + table->TransformLength < src_offset )
   1934      {
   1935        FT_ERROR(( "woff2_open_font: invalid WOFF2 table directory.\n" ));
   1936        error = FT_THROW( Invalid_Table );
   1937        goto Exit;
   1938      }
   1939 
   1940      table->flags      = flags;
   1941      table->src_offset = src_offset;
   1942      table->src_length = table->TransformLength;
   1943      src_offset       += table->TransformLength;
   1944      table->dst_offset = 0;
   1945 
   1946      FT_TRACE2(( "  %c%c%c%c  %08d  %08d   %08lu    %08lu    %08lu\n",
   1947                  (FT_Char)( table->Tag >> 24 ),
   1948                  (FT_Char)( table->Tag >> 16 ),
   1949                  (FT_Char)( table->Tag >> 8  ),
   1950                  (FT_Char)( table->Tag       ),
   1951                  table->FlagByte & 0x3f,
   1952                  ( table->FlagByte >> 6 ) & 0x03,
   1953                  table->dst_length,
   1954                  table->TransformLength,
   1955                  table->src_offset ));
   1956 
   1957      indices[nn] = table;
   1958    }
   1959 
   1960    /* End of last table is uncompressed size. */
   1961    last_table = indices[woff2.num_tables - 1];
   1962 
   1963    woff2.uncompressed_size = last_table->src_offset +
   1964                              last_table->src_length;
   1965    if ( woff2.uncompressed_size < last_table->src_offset )
   1966    {
   1967      error = FT_THROW( Invalid_Table );
   1968      goto Exit;
   1969    }
   1970 
   1971    FT_TRACE2(( "Table directory parsed.\n" ));
   1972 
   1973    /* Check for and read collection directory. */
   1974    woff2.num_fonts      = 1;
   1975    woff2.header_version = 0;
   1976 
   1977    if ( woff2.flavor == TTAG_ttcf )
   1978    {
   1979      FT_TRACE2(( "Font is a TTC, reading collection directory.\n" ));
   1980 
   1981      if ( FT_READ_ULONG( woff2.header_version ) )
   1982        goto Exit;
   1983 
   1984      if ( woff2.header_version != 0x00010000 &&
   1985           woff2.header_version != 0x00020000 )
   1986      {
   1987        error = FT_THROW( Invalid_Table );
   1988        goto Exit;
   1989      }
   1990 
   1991      if ( READ_255USHORT( woff2.num_fonts ) )
   1992        goto Exit;
   1993 
   1994      if ( !woff2.num_fonts )
   1995      {
   1996        error = FT_THROW( Invalid_Table );
   1997        goto Exit;
   1998      }
   1999 
   2000      FT_TRACE4(( "Number of fonts in TTC: %d\n", woff2.num_fonts ));
   2001 
   2002      /* pre-zero pointers within in case of failure */
   2003      if ( FT_NEW_ARRAY( woff2.ttc_fonts, woff2.num_fonts ) )
   2004        goto Exit;
   2005 
   2006      for ( nn = 0; nn < woff2.num_fonts; nn++ )
   2007      {
   2008        WOFF2_TtcFont  ttc_font = woff2.ttc_fonts + nn;
   2009 
   2010 
   2011        if ( READ_255USHORT( ttc_font->num_tables ) )
   2012          goto Exit;
   2013        if ( FT_READ_ULONG( ttc_font->flavor ) )
   2014          goto Exit;
   2015 
   2016        if ( FT_QNEW_ARRAY( ttc_font->table_indices, ttc_font->num_tables ) )
   2017          goto Exit;
   2018 
   2019        FT_TRACE5(( "Number of tables in font %d: %d\n",
   2020                    nn, ttc_font->num_tables ));
   2021 
   2022 #ifdef FT_DEBUG_LEVEL_TRACE
   2023        if ( ttc_font->num_tables )
   2024          FT_TRACE6(( "  Indices: " ));
   2025 #endif
   2026 
   2027        glyf_index = 0;
   2028        loca_index = 0;
   2029 
   2030        for ( j = 0; j < ttc_font->num_tables; j++ )
   2031        {
   2032          FT_UShort    table_index;
   2033          WOFF2_Table  table;
   2034 
   2035 
   2036          if ( READ_255USHORT( table_index ) )
   2037            goto Exit;
   2038 
   2039          FT_TRACE6(( "%hu ", table_index ));
   2040          if ( table_index >= woff2.num_tables )
   2041          {
   2042            FT_ERROR(( "woff2_open_font: invalid table index\n" ));
   2043            error = FT_THROW( Invalid_Table );
   2044            goto Exit;
   2045          }
   2046 
   2047          ttc_font->table_indices[j] = table_index;
   2048 
   2049          table = indices[table_index];
   2050          if ( table->Tag == TTAG_loca )
   2051            loca_index = table_index;
   2052          if ( table->Tag == TTAG_glyf )
   2053            glyf_index = table_index;
   2054        }
   2055 
   2056 #ifdef FT_DEBUG_LEVEL_TRACE
   2057        if ( ttc_font->num_tables )
   2058          FT_TRACE6(( "\n" ));
   2059 #endif
   2060 
   2061        /* glyf and loca must be consecutive */
   2062        if ( glyf_index > 0 || loca_index > 0 )
   2063        {
   2064          if ( glyf_index > loca_index      ||
   2065               loca_index - glyf_index != 1 )
   2066          {
   2067            error = FT_THROW( Invalid_Table );
   2068            goto Exit;
   2069          }
   2070        }
   2071      }
   2072 
   2073      /* Collection directory reading complete. */
   2074      FT_TRACE2(( "WOFF2 collection directory is valid.\n" ));
   2075    }
   2076    else
   2077      woff2.ttc_fonts = NULL;
   2078 
   2079    woff2.compressed_offset = FT_STREAM_POS();
   2080    file_offset             = ROUND4( woff2.compressed_offset +
   2081                                      woff2.totalCompressedSize );
   2082 
   2083    /* Some more checks before we start reading the tables. */
   2084    if ( file_offset > woff2.length )
   2085    {
   2086      error = FT_THROW( Invalid_Table );
   2087      goto Exit;
   2088    }
   2089 
   2090    if ( woff2.metaOffset )
   2091    {
   2092      if ( file_offset != woff2.metaOffset )
   2093      {
   2094        error = FT_THROW( Invalid_Table );
   2095        goto Exit;
   2096      }
   2097      file_offset = ROUND4( woff2.metaOffset + woff2.metaLength );
   2098    }
   2099 
   2100    if ( woff2.privOffset )
   2101    {
   2102      if ( file_offset != woff2.privOffset )
   2103      {
   2104        error = FT_THROW( Invalid_Table );
   2105        goto Exit;
   2106      }
   2107      file_offset = ROUND4( woff2.privOffset + woff2.privLength );
   2108    }
   2109 
   2110    if ( file_offset != ( ROUND4( woff2.length ) ) )
   2111    {
   2112      error = FT_THROW( Invalid_Table );
   2113      goto Exit;
   2114    }
   2115 
   2116    /* Validate requested face index. */
   2117    *num_faces = woff2.num_fonts;
   2118    /* value -(N+1) requests information on index N */
   2119    if ( *face_instance_index < 0 && face_index > 0 )
   2120      face_index--;
   2121 
   2122    if ( face_index >= woff2.num_fonts )
   2123    {
   2124      if ( *face_instance_index >= 0 )
   2125      {
   2126        error = FT_THROW( Invalid_Argument );
   2127        goto Exit;
   2128      }
   2129      else
   2130        face_index = 0;
   2131    }
   2132 
   2133    /* Only retain tables of the requested face in a TTC. */
   2134    if ( woff2.header_version )
   2135    {
   2136      WOFF2_TtcFont  ttc_font = woff2.ttc_fonts + face_index;
   2137 
   2138 
   2139      if ( ttc_font->num_tables == 0 || ttc_font->num_tables > 0xFFFU )
   2140      {
   2141        FT_ERROR(( "woff2_open_font: invalid WOFF2 CollectionFontEntry\n" ));
   2142        error = FT_THROW( Invalid_Table );
   2143        goto Exit;
   2144      }
   2145 
   2146      /* Create a temporary array. */
   2147      if ( FT_QNEW_ARRAY( temp_indices,
   2148                          ttc_font->num_tables ) )
   2149        goto Exit;
   2150 
   2151      FT_TRACE4(( "Storing tables for TTC face index %d.\n", face_index ));
   2152      for ( nn = 0; nn < ttc_font->num_tables; nn++ )
   2153        temp_indices[nn] = indices[ttc_font->table_indices[nn]];
   2154 
   2155      /* Resize array to required size. */
   2156      if ( FT_QRENEW_ARRAY( indices,
   2157                            woff2.num_tables,
   2158                            ttc_font->num_tables ) )
   2159        goto Exit;
   2160 
   2161      for ( nn = 0; nn < ttc_font->num_tables; nn++ )
   2162        indices[nn] = temp_indices[nn];
   2163 
   2164      FT_FREE( temp_indices );
   2165 
   2166      /* Change header values. */
   2167      woff2.flavor     = ttc_font->flavor;
   2168      woff2.num_tables = ttc_font->num_tables;
   2169    }
   2170 
   2171    /* We need to allocate this much at the minimum. */
   2172    sfnt_size = 12 + woff2.num_tables * 16UL;
   2173    /* This is what we normally expect.                              */
   2174    /* Initially trust `totalSfntSize' and change later as required. */
   2175    if ( woff2.totalSfntSize > sfnt_size )
   2176    {
   2177      /* However, adjust the value to something reasonable. */
   2178 
   2179      /* Factor 64 is heuristic. */
   2180      if ( ( woff2.totalSfntSize >> 6 ) > woff2.length )
   2181        sfnt_size = woff2.length << 6;
   2182      else
   2183        sfnt_size = woff2.totalSfntSize;
   2184 
   2185      if ( sfnt_size >= MAX_SFNT_SIZE )
   2186        sfnt_size = MAX_SFNT_SIZE;
   2187 
   2188 #ifdef FT_DEBUG_LEVEL_TRACE
   2189      if ( sfnt_size != woff2.totalSfntSize )
   2190        FT_TRACE4(( "adjusting estimate of uncompressed font size"
   2191                    " to %lu bytes\n",
   2192                    sfnt_size ));
   2193 #endif
   2194    }
   2195 
   2196    /* Write sfnt header. */
   2197    if ( FT_QALLOC( sfnt, sfnt_size ) ||
   2198         FT_NEW( sfnt_stream )        )
   2199      goto Exit;
   2200 
   2201    {
   2202      FT_Byte*  sfnt_header = sfnt;
   2203 
   2204      FT_Int  entrySelector = FT_MSB( woff2.num_tables );
   2205      FT_Int  searchRange   = ( 1 << entrySelector ) * 16;
   2206      FT_Int  rangeShift    = woff2.num_tables * 16 - searchRange;
   2207 
   2208 
   2209      WRITE_ULONG ( sfnt_header, woff2.flavor );
   2210      WRITE_USHORT( sfnt_header, woff2.num_tables );
   2211      WRITE_USHORT( sfnt_header, searchRange );
   2212      WRITE_USHORT( sfnt_header, entrySelector );
   2213      WRITE_USHORT( sfnt_header, rangeShift );
   2214    }
   2215 
   2216    info.header_checksum = compute_ULong_sum( sfnt, 12 );
   2217 
   2218    /* Sort tables by tag. */
   2219    ft_qsort( indices,
   2220              woff2.num_tables,
   2221              sizeof ( WOFF2_Table ),
   2222              compare_tags );
   2223 
   2224    /* reject fonts that have multiple tables with the same tag */
   2225    for ( nn = 1; nn < woff2.num_tables; nn++ )
   2226    {
   2227      FT_Tag  tag = indices[nn]->Tag;
   2228 
   2229 
   2230      if ( tag == indices[nn - 1]->Tag )
   2231      {
   2232        FT_ERROR(( "woff2_open_font:"
   2233                   " multiple tables with tag `%c%c%c%c'.\n",
   2234                   (FT_Char)( tag >> 24 ),
   2235                   (FT_Char)( tag >> 16 ),
   2236                   (FT_Char)( tag >> 8  ),
   2237                   (FT_Char)( tag       ) ));
   2238        error = FT_THROW( Invalid_Table );
   2239        goto Exit;
   2240      }
   2241    }
   2242 
   2243    if ( woff2.uncompressed_size < 1 )
   2244    {
   2245      error = FT_THROW( Invalid_Table );
   2246      goto Exit;
   2247    }
   2248 
   2249    /* We must not blindly trust `uncompressed_size` since its   */
   2250    /* value might be corrupted.  If it is too large, reject the */
   2251    /* font.  In other words, we don't accept a WOFF2 font that  */
   2252    /* expands to something larger than MAX_SFNT_SIZE.  If ever  */
   2253    /* necessary, this limit can be easily adjusted.             */
   2254    if ( woff2.uncompressed_size > MAX_SFNT_SIZE )
   2255    {
   2256      FT_ERROR(( "Uncompressed font too large.\n" ));
   2257      error = FT_THROW( Array_Too_Large );
   2258      goto Exit;
   2259    }
   2260 
   2261    /* Allocate memory for uncompressed table data. */
   2262    if ( FT_QALLOC( uncompressed_buf, woff2.uncompressed_size ) ||
   2263         FT_FRAME_ENTER( woff2.totalCompressedSize )            )
   2264      goto Exit;
   2265 
   2266    /* Uncompress the stream. */
   2267    error = woff2_decompress( uncompressed_buf,
   2268                              woff2.uncompressed_size,
   2269                              stream->cursor,
   2270                              woff2.totalCompressedSize );
   2271 
   2272    FT_FRAME_EXIT();
   2273 
   2274    if ( error )
   2275      goto Exit;
   2276 
   2277    error = reconstruct_font( uncompressed_buf,
   2278                              woff2.uncompressed_size,
   2279                              indices,
   2280                              &woff2,
   2281                              &info,
   2282                              &sfnt,
   2283                              &sfnt_size,
   2284                              memory );
   2285 
   2286    if ( error )
   2287      goto Exit;
   2288 
   2289    /* Resize `sfnt' to actual size of sfnt stream. */
   2290    if ( woff2.actual_sfnt_size < sfnt_size )
   2291    {
   2292      FT_TRACE5(( "Trimming sfnt stream from %lu to %lu.\n",
   2293                  sfnt_size, woff2.actual_sfnt_size ));
   2294      if ( FT_QREALLOC( sfnt,
   2295                        (FT_ULong)( sfnt_size ),
   2296                        (FT_ULong)( woff2.actual_sfnt_size ) ) )
   2297        goto Exit;
   2298    }
   2299 
   2300    /* `reconstruct_font' has done all the work. */
   2301    /* Swap out stream and return.               */
   2302    FT_Stream_OpenMemory( sfnt_stream, sfnt, woff2.actual_sfnt_size );
   2303    sfnt_stream->memory = stream->memory;
   2304    sfnt_stream->close  = stream_close;
   2305 
   2306    FT_Stream_Free(
   2307      face->root.stream,
   2308      ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
   2309 
   2310    face->root.stream      = sfnt_stream;
   2311    face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
   2312 
   2313    /* Set face_index to 0 or -1. */
   2314    if ( *face_instance_index >= 0 )
   2315      *face_instance_index = 0;
   2316    else
   2317      *face_instance_index = -1;
   2318 
   2319    FT_TRACE2(( "woff2_open_font: SFNT synthesized.\n" ));
   2320 
   2321  Exit:
   2322    FT_FREE( tables );
   2323    FT_FREE( indices );
   2324    FT_FREE( uncompressed_buf );
   2325    FT_FREE( info.x_mins );
   2326 
   2327    if ( woff2.ttc_fonts )
   2328    {
   2329      WOFF2_TtcFont  ttc_font = woff2.ttc_fonts;
   2330 
   2331 
   2332      for ( nn = 0; nn < woff2.num_fonts; nn++ )
   2333      {
   2334        FT_FREE( ttc_font->table_indices );
   2335        ttc_font++;
   2336      }
   2337 
   2338      FT_FREE( woff2.ttc_fonts );
   2339    }
   2340 
   2341    if ( error )
   2342    {
   2343      FT_FREE( sfnt );
   2344      if ( sfnt_stream )
   2345      {
   2346        FT_Stream_Close( sfnt_stream );
   2347        FT_FREE( sfnt_stream );
   2348      }
   2349    }
   2350 
   2351    return error;
   2352  }
   2353 
   2354 
   2355 #undef READ_255USHORT
   2356 #undef READ_BASE128
   2357 #undef ROUND4
   2358 #undef WRITE_USHORT
   2359 #undef WRITE_ULONG
   2360 #undef WRITE_SHORT
   2361 #undef WRITE_SFNT_BUF
   2362 #undef WRITE_SFNT_BUF_AT
   2363 
   2364 #undef N_CONTOUR_STREAM
   2365 #undef N_POINTS_STREAM
   2366 #undef FLAG_STREAM
   2367 #undef GLYPH_STREAM
   2368 #undef COMPOSITE_STREAM
   2369 #undef BBOX_STREAM
   2370 #undef INSTRUCTION_STREAM
   2371 
   2372 #else /* !FT_CONFIG_OPTION_USE_BROTLI */
   2373 
   2374  /* ANSI C doesn't like empty source files */
   2375  typedef int  sfwoff2_dummy_;
   2376 
   2377 #endif /* !FT_CONFIG_OPTION_USE_BROTLI */
   2378 
   2379 
   2380 /* END */