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