shithub: freetype+ttf2subf

Download patch

ref: 4d9b3d1d506c2da2cc078369ed130fb2b6994bb2
parent: e3953e5410eaeec7ae49dbda26be6e4b1ca5d26c
author: Nikhil Ramakrishnan <[email protected]>
date: Mon Jul 15 22:45:03 EDT 2019

[woff2] Reconstruct `loca', `hmtx', and swap out stream.

Add necessary functions to reconstruct loca and hmtx tables (the two
remaining tables that can have a transform).  `woff2_open_font' is
now capable of loading a woff2 font face.  This code may still need
more refining and better memory management.

* include/freetype/internal/wofftypes.h (WOFF2_HeaderRec): Add total
(final) size of sfnt stream.

(WOFF2_InfoRec): Add header checksum value.

* src/sfnt/sfobjs.c (sfnt_open_font): Change `face_instance_index'
parameter to its pointer so its value can be modified by
`woff2_open_font'.

* src/sfnt/sfwoff2.c: (WRITE_SFNT_BUF_AT): New macro to write into
sfnt buffer at given position.

(write_buf): Add parameter `extend_buf' which allows caller to
specify whether buffer should be reallocated before copying data.

(WRITE_SFNT_BUF): Updated.

(pad4, store_loca, reconstruct_htmx): New functions.

(reconstruct_glyf): Calculate loca values and store them.

(reconstruct_font): Call `reconstruct_hmtx', write table record
entries, and calculate table checksums.  Also calculate font
checksum and update `checksumAdjustment' entry in head table.

(woff2_open_font): Open stream for sfnt buffer, swap out input
stream and return.

* src/sfnt/sfwoff2.h (woff2_open_font): Modify parameter to accept
pointer to `face_index'.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,45 @@
 2019-08-27  Nikhil Ramakrishnan  <[email protected]>
 
+	[woff2] Reconstruct `loca', `hmtx', and swap out stream.
+
+	Add necessary functions to reconstruct loca and hmtx tables (the two
+	remaining tables that can have a transform).  `woff2_open_font' is
+	now capable of loading a woff2 font face.  This code may still need
+	more refining and better memory management.
+
+	* include/freetype/internal/wofftypes.h (WOFF2_HeaderRec): Add total
+	(final) size of sfnt stream.
+
+	(WOFF2_InfoRec): Add header checksum value.
+
+	* src/sfnt/sfobjs.c (sfnt_open_font): Change `face_instance_index'
+	parameter to its pointer so its value can be modified by
+	`woff2_open_font'.
+
+	* src/sfnt/sfwoff2.c: (WRITE_SFNT_BUF_AT): New macro to write into
+	sfnt buffer at given position.
+
+	(write_buf): Add parameter `extend_buf' which allows caller to
+	specify whether buffer should be reallocated before copying data.
+
+	(WRITE_SFNT_BUF): Updated.
+
+	(pad4, store_loca, reconstruct_htmx): New functions.
+
+	(reconstruct_glyf): Calculate loca values and store them.
+
+	(reconstruct_font): Call `reconstruct_hmtx', write table record
+	entries, and calculate table checksums.  Also calculate font
+	checksum and update `checksumAdjustment' entry in head table.
+
+	(woff2_open_font): Open stream for sfnt buffer, swap out input
+	stream and return.
+
+	* src/sfnt/sfwoff2.h (woff2_open_font): Modify parameter to accept
+	pointer to `face_index'.
+
+2019-08-27  Nikhil Ramakrishnan  <[email protected]>
+
 	[woff2] Reconstruct transformed `glyf' table.
 
 	Reconstruct `glyf' table if it is transformed in the uncompressed
--- a/include/freetype/internal/wofftypes.h
+++ b/include/freetype/internal/wofftypes.h
@@ -173,9 +173,10 @@
     FT_ULong   privLength;
 
     FT_ULong   uncompressed_size;
-    FT_UInt64  compressed_offset;
+    FT_ULong   compressed_offset;
     FT_ULong   header_version;
     FT_UShort  num_fonts;
+    FT_ULong   total_sfnt_size;
 
     WOFF2_TtcFont  ttc_fonts;
 
@@ -203,6 +204,7 @@
    */
   typedef struct  WOFF2_InfoRec_
   {
+    FT_ULong   header_checksum;
     FT_UShort  num_glyphs;
     FT_UShort  num_hmetrics;
     FT_Short*  x_mins;
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -343,7 +343,7 @@
   static FT_Error
   sfnt_open_font( FT_Stream  stream,
                   TT_Face    face,
-                  FT_Int     face_instance_index )
+                  FT_Int*    face_instance_index )
   {
     FT_Memory  memory = stream->memory;
     FT_Error   error;
@@ -532,7 +532,7 @@
 
     FT_TRACE2(( "SFNT driver\n" ));
 
-    error = sfnt_open_font( stream, face, face_instance_index );
+    error = sfnt_open_font( stream, face, &face_instance_index );
     if ( error )
       return error;
 
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -44,7 +44,7 @@
 
 #define READ_BASE128( var )    FT_SET_ERROR( ReadBase128( stream, &var ) )
 
-#define ROUND4( var )          ( var + 3 ) & ~3
+#define ROUND4( var )          ( ( var + 3 ) & ~3 )
 
 #define WRITE_USHORT( p, v )                \
           do                                \
@@ -73,8 +73,11 @@
           } while ( 0 )
 
 #define WRITE_SFNT_BUF( buf, s ) \
-          write_buf( &sfnt, &dest_offset, buf, s, memory )
+          write_buf( &sfnt, &dest_offset, buf, s, memory, TRUE )
 
+#define WRITE_SFNT_BUF_AT( offset, buf, s ) \
+          write_buf( &sfnt, &offset, buf, s, memory, FALSE )
+
 #define N_CONTOUR_STREAM    0
 #define N_POINTS_STREAM     1
 #define FLAG_STREAM         2
@@ -205,7 +208,8 @@
              FT_ULong*  offset,
              FT_Byte*   src,
              FT_ULong   size,
-             FT_Memory  memory )
+             FT_Memory  memory,
+             FT_Bool    extend_buf )
   {
     FT_Error  error = FT_Err_Ok;
     /* We are reallocating memory for `dst', so its pointer may change. */
@@ -218,10 +222,13 @@
     /* DEBUG - Remove later */
     /* FT_TRACE2(( "Reallocating %lu to %lu.\n", *offset, (*offset + size) )); */
     /* Reallocate `dst'. */
-    if ( FT_REALLOC( dst,
-                     (FT_ULong)( *offset ),
-                     (FT_ULong)( *offset + size ) ) )
-      goto Exit;
+    if( extend_buf )
+    {
+      if ( FT_REALLOC( dst,
+                      (FT_ULong)( *offset ),
+                      (FT_ULong)( *offset + size ) ) )
+        goto Exit;
+    }
 
     /* Copy data. */
     ft_memcpy( dst + *offset, src, size );
@@ -235,38 +242,30 @@
   }
 
 
-  static FT_Offset
-  CollectionHeaderSize( FT_ULong header_version,
-                        FT_UShort num_fonts )
+  static FT_Error
+  pad4( FT_Byte**  sfnt_bytes,
+        FT_ULong*  out_offset,
+        FT_Memory  memory )
   {
-    FT_Offset size = 0;
-    if (header_version == 0x00020000)
-      size += 12;             /* ulDsig{Tag,Length,Offset} */
-    if (header_version == 0x00010000 || header_version == 0x00020000) {
-      size += 12              /* TTCTag, Version, numFonts */
-        + ( 4 * num_fonts );  /* OffsetTable[numFonts]     */
-    }
-    return size;
-  }
+    FT_Byte*  sfnt        = *sfnt_bytes;
+    FT_ULong  dest_offset = *out_offset;
 
+    FT_Byte   zeroes[] = { 0, 0, 0 };
+    FT_ULong  pad_bytes;
 
-  static FT_UInt64
-  compute_first_table_offset( const WOFF2_Header  woff2 )
-  {
-    FT_Int  nn;
-    FT_Offset  offset = WOFF2_SFNT_HEADER_SIZE +
-                        ( WOFF2_SFNT_ENTRY_SIZE *
-                        (FT_Offset)( woff2->num_tables ) );
-    if(woff2->header_version)
+    if ( dest_offset + 3 < dest_offset )
+      return FT_THROW( Invalid_Table );
+
+    pad_bytes = ROUND4( dest_offset ) - dest_offset;
+    if ( pad_bytes > 0 )
     {
-      offset = CollectionHeaderSize( woff2->header_version,
-                                     woff2->num_fonts )
-               + WOFF2_SFNT_HEADER_SIZE * woff2->num_fonts;
-      for ( nn = 0; nn< woff2->num_fonts; nn++ ) {
-        offset += WOFF2_SFNT_ENTRY_SIZE * woff2->ttc_fonts[nn].num_tables;
-      }
+      if( WRITE_SFNT_BUF( &zeroes[0], pad_bytes ) )
+        return FT_THROW( Invalid_Table );
     }
-    return offset;
+
+    *sfnt_bytes = sfnt;
+    *out_offset = dest_offset;
+    return FT_Err_Ok;
   }
 
 
@@ -718,16 +717,76 @@
 
 
   static FT_Error
-  reconstruct_glyf( FT_Stream       stream,
-                    WOFF2_Table     glyf_table,
-                    FT_ULong*       glyf_checksum,
-                    WOFF2_Table     loca_table,
-                    FT_ULong*       loca_checksum,
-                    FT_Byte**       sfnt_bytes,
-                    FT_ULong*       out_offset,
-                    WOFF2_Info      info,
-                    FT_Memory       memory )
+  store_loca( FT_ULong*  loca_values,
+              FT_ULong   loca_values_size,
+              FT_UShort  index_format,
+              FT_ULong*  checksum,
+              FT_Byte**  sfnt_bytes,
+              FT_ULong*  out_offset,
+              FT_Memory  memory )
   {
+    FT_Error  error       = FT_Err_Ok;
+    FT_Byte*  sfnt        = *sfnt_bytes;
+    FT_ULong  dest_offset = *out_offset;
+
+    FT_Byte*  loca_buf = NULL;
+    FT_Byte*  dst      = NULL;
+
+    FT_Int    i             = 0;
+    FT_ULong  loca_buf_size;
+
+    const FT_ULong  offset_size = index_format ? 4 : 2;
+
+    if( ( loca_values_size << 2 ) >> 2 != loca_values_size )
+      goto Fail;
+
+    loca_buf_size = loca_values_size * offset_size;
+    if( FT_NEW_ARRAY( loca_buf, loca_buf_size ) )
+      goto Fail;
+
+    dst = loca_buf;
+    for ( i = 0; i < loca_values_size; i++ )
+    {
+      FT_ULong  value = loca_values[i];
+      if( index_format )
+        WRITE_ULONG( dst, value );
+      else
+        WRITE_USHORT( dst, ( value >> 1 ) );
+    }
+
+    *checksum = compute_ULong_sum( loca_buf, loca_buf_size );
+    /* Write loca table to sfnt buffer. */
+    if( WRITE_SFNT_BUF( loca_buf, loca_buf_size ) )
+      goto Fail;
+
+    /* Set pointer `sfnt_bytes' to its correct value. */
+    *sfnt_bytes = sfnt;
+    *out_offset = dest_offset;
+
+    FT_FREE( loca_buf );
+    return error;
+
+    Fail:
+      if( !error )
+        error = FT_THROW( Invalid_Table );
+
+      FT_FREE( loca_buf );
+
+      return error;
+  }
+
+
+  static FT_Error
+  reconstruct_glyf( FT_Stream    stream,
+                    WOFF2_Table  glyf_table,
+                    FT_ULong*    glyf_checksum,
+                    WOFF2_Table  loca_table,
+                    FT_ULong*    loca_checksum,
+                    FT_Byte**    sfnt_bytes,
+                    FT_ULong*    out_offset,
+                    WOFF2_Info   info,
+                    FT_Memory    memory )
+  {
     FT_Error  error = FT_Err_Ok;
     FT_Byte*  sfnt  = *sfnt_bytes;
 
@@ -766,8 +825,11 @@
     if( FT_READ_USHORT( index_format ) )
       goto Fail;
 
-    FT_TRACE2(( "Num_glyphs = %u; index_format = %u\n", num_glyphs, index_format ));
+    FT_TRACE2(( "Num_glyphs = %u; index_format = %u\n",
+                num_glyphs, index_format ));
 
+    info->num_glyphs = num_glyphs;
+
     /* Calculate expected length of loca and compare.          */
     /* See https://www.w3.org/TR/WOFF2/#conform-mustRejectLoca */
     /* index_format = 0 => Short version `loca'.               */
@@ -794,7 +856,7 @@
       substreams[i].size   = substream_size;
 
       /* DEBUG - Remove later */
-      FT_TRACE2(( "Substream %d: offset = %lu; size = %lu;\n",
+      FT_TRACE2(( "  Substream %d: offset = %lu; size = %lu;\n",
                   i, substreams[i].offset, substreams[i].size ));
       offset += substream_size;
     }
@@ -917,8 +979,8 @@
         FT_ULong   flag_size;
         FT_ULong   triplet_size;
         FT_ULong   triplet_bytes_used;
-        FT_Byte*   flags_buf;
-        FT_Byte*   triplet_buf;
+        FT_Byte*   flags_buf   = NULL;
+        FT_Byte*   triplet_buf = NULL;
         FT_UShort  instruction_size;
         FT_ULong   size_needed;
         FT_Int     end_point;
@@ -1021,6 +1083,7 @@
         if( FT_STREAM_SEEK( substreams[INSTRUCTION_STREAM].offset )    ||
             FT_STREAM_READ( glyph_buf + glyph_size, instruction_size ) )
           goto Fail;
+        substreams[INSTRUCTION_STREAM].offset += instruction_size;
         glyph_size += instruction_size;
 
         if( store_points( total_n_points, points, n_contours,
@@ -1045,6 +1108,9 @@
       if( WRITE_SFNT_BUF( glyph_buf, glyph_size ) )
         goto Fail;
 
+      if( pad4( &sfnt, &dest_offset, memory ) )
+        goto Fail;
+
       *glyf_checksum += compute_ULong_sum( glyph_buf, glyph_size );
 
       /* Store x_mins, may be required to reconstruct `hmtx'. */
@@ -1053,11 +1119,22 @@
     }
 
     glyf_table->dst_length = dest_offset - glyf_table->dst_offset;
+    loca_table->dst_offset = dest_offset;
+    /* loca[n] will be equal the length of the `glyf' table. */
+    loca_values[num_glyphs] = glyf_table->dst_length;
 
+    if( store_loca( loca_values, num_glyphs + 1, index_format,
+                    loca_checksum, &sfnt, &dest_offset, memory ) )
+      goto Fail;
 
-    /* TODO Reconstruct `loca' table and set its `dst_length'. */
+    loca_table->dst_length = dest_offset - loca_table->dst_offset;
 
-    /* Set pointer of `sfnt_bytes' to its correct value. */
+    FT_TRACE2(( "  loca table info:\n" ));
+    FT_TRACE2(( "    dst_offset = %lu\n", loca_table->dst_offset ));
+    FT_TRACE2(( "    dst_length = %lu\n", loca_table->dst_length ));
+    FT_TRACE2(( "    checksum = %08x\n", *loca_checksum ));
+
+    /* Set pointer `sfnt_bytes' to its correct value. */
     *sfnt_bytes = sfnt;
     *out_offset = dest_offset;
     /* DEBUG - Remove later */
@@ -1086,7 +1163,143 @@
   }
 
 
+  /* XXX What if hmtx is transformed but glyf is not? */
   static FT_Error
+  reconstruct_hmtx( FT_Stream  stream,
+                    FT_ULong   transformed_size,
+                    FT_UShort  num_glyphs,
+                    FT_UShort  num_hmetrics,
+                    FT_Short*  x_mins,
+                    FT_ULong*  checksum,
+                    FT_Byte**  sfnt_bytes,
+                    FT_ULong*  out_offset,
+                    FT_Memory  memory )
+  {
+    FT_Error  error       = FT_Err_Ok;
+    FT_Byte*  sfnt        = *sfnt_bytes;
+    FT_ULong  dest_offset = *out_offset;
+
+    FT_Byte   hmtx_flags;
+    FT_Bool   has_proportional_lsbs, has_monospace_lsbs;
+    FT_ULong  hmtx_table_size;
+    FT_Int    i;
+
+    FT_UShort*  advance_widths = NULL;
+    FT_Short*   lsbs           = NULL;
+    FT_Byte*    hmtx_table     = NULL;
+    FT_Byte*    dst            = NULL;
+
+    FT_TRACE2(( "Reconstructing hmtx.\n" ));
+
+    if( FT_READ_BYTE( hmtx_flags ) )
+      goto Fail;
+
+    has_proportional_lsbs = ( hmtx_flags & 1 ) == 0;
+    has_monospace_lsbs    = ( hmtx_flags & 2 ) == 0;
+
+    /* Bits 2-7 are reserved and MUST be zero. */
+    if ( ( hmtx_flags & 0xFC ) != 0 )
+      goto Fail;
+
+    /* Are you REALLY transformed? */
+    if ( has_proportional_lsbs && has_monospace_lsbs )
+      goto Fail;
+
+    /* Cannot have a transformed `hmtx' without `glyf'. */
+    if ( ( num_hmetrics > num_glyphs ) ||
+         ( num_hmetrics < 1 )          )
+      goto Fail;
+
+    /* Must have atleast one entry. */
+    if ( num_hmetrics < 1 )
+      goto Fail;
+
+    if ( FT_NEW_ARRAY( advance_widths, num_hmetrics ) ||
+         FT_NEW_ARRAY( lsbs, num_glyphs )             )
+      goto Fail;
+
+    /* Read `advanceWidth' stream. Always present. */
+    for ( i = 0; i < num_hmetrics; i++ )
+    {
+      FT_UShort  advance_width;
+
+      if ( FT_READ_USHORT( advance_width ) )
+        goto Fail;
+
+    advance_widths[i] = advance_width;
+    }
+
+    /* lsb values for proportional glyphs. */
+    for ( i = 0; i < num_hmetrics; i++ )
+    {
+      FT_Short  lsb;
+
+      if ( has_proportional_lsbs )
+      {
+        if ( FT_READ_SHORT( lsb ) )
+          goto Fail;
+      }
+      else
+        lsb = x_mins[i];
+
+      lsbs[i] = lsb;
+    }
+
+    /* lsb values for monospaced glyphs */
+    for ( i = num_hmetrics; i < num_glyphs; i++ )
+    {
+      FT_Short  lsb;
+
+      if ( has_monospace_lsbs )
+      {
+        if ( FT_READ_SHORT( lsb ) )
+          goto Fail;
+      }
+      else
+        lsb = x_mins[i];
+
+      lsbs[i] = lsb;
+    }
+
+    /* Build the hmtx table. */
+    hmtx_table_size = 2 * num_hmetrics + 2 * num_glyphs;
+    if( FT_NEW_ARRAY( hmtx_table, hmtx_table_size ) )
+      goto Fail;
+
+    dst = hmtx_table;
+    FT_TRACE2(( "hmtx values: \n" ));
+    for( i = 0; i < num_glyphs; i++ )
+    {
+      if( i < num_hmetrics )
+      {
+        WRITE_SHORT( dst, advance_widths[i] );
+        FT_TRACE2(( "%d ", advance_widths[i] ));
+      }
+
+      WRITE_SHORT( dst, lsbs[i] );
+      FT_TRACE2(( "%d ", lsbs[i] ));
+    }
+
+    FT_TRACE2(( "\n" ));
+    *checksum = compute_ULong_sum( hmtx_table, hmtx_table_size );
+    /* Write hmtx table to sfnt buffer. */
+    if( WRITE_SFNT_BUF( hmtx_table, hmtx_table_size ) )
+      goto Fail;
+
+    /* Set pointer `sfnt_bytes' to its correct value. */
+    *sfnt_bytes = sfnt;
+    *out_offset = dest_offset;
+
+    return error;
+
+    Fail:
+      if( !error )
+        error = FT_THROW( Invalid_Table );
+      return error;
+  }
+
+
+  static FT_Error
   reconstruct_font( FT_Byte*      transformed_buf,
                     FT_ULong      transformed_buf_size,
                     WOFF2_Table*  indices,
@@ -1095,9 +1308,10 @@
                     FT_Byte**     sfnt_bytes,
                     FT_Memory     memory )
   {
-    FT_Error    error      = FT_Err_Ok;
-    FT_Stream   stream     = NULL;
-    FT_Byte*    buf_cursor = NULL;
+    FT_Error   error               = FT_Err_Ok;
+    FT_Stream  stream              = NULL;
+    FT_Byte*   buf_cursor          = NULL;
+    FT_Byte*   table_entry         = NULL;
 
     /* We are reallocating memory for `sfnt', so its pointer may change. */
     FT_Byte*   sfnt       = *sfnt_bytes;
@@ -1105,11 +1319,15 @@
     FT_UShort  num_tables  = woff2->num_tables;
     FT_ULong   dest_offset = 12 + num_tables * 16UL;
 
-    FT_ULong  checksum      = 0;
-    FT_ULong  loca_checksum = 0;
-    FT_Int    nn            = 0;
+    FT_ULong   checksum      = 0;
+    FT_ULong   loca_checksum = 0;
+    FT_Int     nn            = 0;
     FT_UShort  num_hmetrics;
+    FT_ULong   font_checksum = info->header_checksum;
 
+    FT_ULong     table_entry_offset = 12;
+    WOFF2_Table  head_table;
+
     /* Few table checks before reconstruction. */
     /* `glyf' must be present with `loca'. */
     const WOFF2_Table glyf_table = find_table( indices, num_tables,
@@ -1135,6 +1353,10 @@
         }
     }
 
+    /* Create buffer for table entries. */
+    if ( FT_NEW_ARRAY( table_entry, 16 ) )
+      goto Fail;
+
     /* Create a stream for the uncompressed buffer. */
     if ( FT_NEW( stream ) )
       return FT_THROW( Invalid_Table );
@@ -1180,7 +1402,9 @@
         {
           if( table.src_length < 12 )
             return FT_THROW( Invalid_Table );
+
           buf_cursor = transformed_buf + table.src_offset + 8;
+          /* Set checkSumAdjustment = 0 */
           WRITE_ULONG( buf_cursor, 0 );
         }
         table.dst_offset = dest_offset;
@@ -1187,7 +1411,7 @@
         checksum = compute_ULong_sum( transformed_buf + table.src_offset,
                                      table.src_length );
         /* DEBUG - Remove later */
-        FT_TRACE2(( "Checksum = %u\n", checksum ));
+        FT_TRACE2(( "Checksum = %08x\n", checksum ));
 
         if( WRITE_SFNT_BUF( transformed_buf + table.src_offset,
                             table.src_length ) )
@@ -1206,17 +1430,80 @@
                                 &sfnt, &dest_offset, info,
                                 memory ) )
             return FT_THROW( Invalid_Table );
+        FT_TRACE2(("glyf checksum is %08x\n", checksum));
         }
+        else if( table.Tag == TTAG_loca )
+        {
+          checksum = loca_checksum;
+        }
+        else if( table.Tag == TTAG_hmtx )
+        {
+          table.dst_offset = dest_offset;
+          if( reconstruct_hmtx( stream, table.src_length, info->num_glyphs,
+                                info->num_hmetrics, info->x_mins, &checksum,
+                                &sfnt, &dest_offset, memory ) )
+            return FT_THROW( Invalid_Table );
+        }
+        else
+        {
+          /* Unknown transform */
+          FT_ERROR(( "Unknown table transform.\n" ));
+          return FT_THROW( Invalid_Table );
+        }
+      }
 
-        /* TODO reconstruct transformed loca and hmtx! */
+      font_checksum += checksum;
+      buf_cursor = &table_entry[0];
+      WRITE_ULONG( buf_cursor, table.Tag );
+      WRITE_ULONG( buf_cursor, checksum );
+      WRITE_ULONG( buf_cursor, table.dst_offset );
+      WRITE_ULONG( buf_cursor, table.dst_length );
+
+      WRITE_SFNT_BUF_AT( table_entry_offset, table_entry, 16 );
+
+      /* Update checksum. */
+      font_checksum += compute_ULong_sum( table_entry, 16 );
+
+      if( pad4( &sfnt, &dest_offset, memory ) )
+        goto Fail;
+
+      /* Sanity check. */
+      if ( (FT_ULong)( table.dst_offset + table.dst_length ) > dest_offset )
+      {
+        FT_ERROR(( "Table was partially written.\n" ));
+        goto Fail;
       }
     }
 
+    /* Update `head' checkSumAdjustment. */
+    head_table = find_table( indices, num_tables, TTAG_head );
+    if ( head_table )
+    {
+      if ( head_table->dst_length < 12 )
+        goto Fail;
+    }
+    buf_cursor = sfnt + head_table->dst_offset + 8;
+    font_checksum = 0xB1B0AFBA - font_checksum;
+    WRITE_ULONG( buf_cursor, font_checksum );
+
+    FT_TRACE2(( "Final checksum = %u\n", font_checksum ));
+
+    woff2->total_sfnt_size = dest_offset;
+
     /* Set pointer of sfnt stream to its correct value. */
     *sfnt_bytes = sfnt;
-    return FT_Err_Ok;
+    FT_FREE( table_entry );
+    return error;
 
-    /* TODO delete the uncompressed stream after everything is done. */
+    Fail:
+      if( !error )
+        error = FT_THROW( Invalid_Table );
+
+      FT_FREE( table_entry );
+
+      return error;
+
+    /* TODO free the uncompressed stream after everything is done. */
   }
 
 
@@ -1226,10 +1513,11 @@
   FT_LOCAL_DEF( FT_Error )
   woff2_open_font( FT_Stream  stream,
                    TT_Face    face,
-                   FT_Int     face_index )
+                   FT_Int*    face_instance_index )
   {
-    FT_Memory        memory = stream->memory;
-    FT_Error         error  = FT_Err_Ok;
+    FT_Memory        memory     = stream->memory;
+    FT_Error         error      = FT_Err_Ok;
+    FT_Int           face_index = *face_instance_index;
 
     WOFF2_HeaderRec  woff2;
     WOFF2_InfoRec    info;
@@ -1246,7 +1534,6 @@
 
     FT_UInt          glyf_index;
     FT_UInt          loca_index;
-    FT_UInt64        first_table_offset;
     FT_UInt64        file_offset;
 
     FT_Byte*         sfnt        = NULL;
@@ -1490,9 +1777,6 @@
       FT_TRACE2(( "WOFF2 collection dirtectory is valid.\n" ));
     }
 
-    first_table_offset = compute_first_table_offset( &woff2 );
-    FT_TRACE2(( "Offset to first table: %ld\n", first_table_offset ));
-
     woff2.compressed_offset = FT_STREAM_POS();
     file_offset = ROUND4( woff2.compressed_offset +
                           woff2.totalCompressedSize );
@@ -1551,12 +1835,11 @@
       /* Change header values. */
       woff2.flavor     = ttc_font->flavor;
       woff2.num_tables = ttc_font->num_tables;
-
     }
 
     /* Write sfnt header. */
     if ( FT_ALLOC( sfnt, 12 + woff2.num_tables * 16UL ) ||
-         FT_NEW( sfnt_stream )                         )
+         FT_NEW( sfnt_stream )                          )
       goto Exit;
 
     sfnt_header = sfnt;
@@ -1584,6 +1867,7 @@
       WRITE_USHORT( sfnt_header, entrySelector );
       WRITE_USHORT( sfnt_header, rangeShift );
 
+      info.header_checksum = compute_ULong_sum( sfnt, 12 );
     }
 
     /* Sort tables by tag. */
@@ -1628,9 +1912,24 @@
     reconstruct_font( uncompressed_buf, woff2.uncompressed_size,
                       indices, &woff2, &info, &sfnt, memory );
 
-    /* TODO Write table entries. */
+    /* reconstruct_font has done all the work. */
+    /* Swap out stream and return.             */
+    FT_Stream_OpenMemory( sfnt_stream, sfnt, woff2.total_sfnt_size );
+    sfnt_stream->memory = stream->memory;
+    sfnt_stream->close  = stream_close;
 
-    error = FT_THROW( Unimplemented_Feature );
+    FT_Stream_Free(
+      face->root.stream,
+      ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
+
+    face->root.stream = sfnt_stream;
+
+    face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
+
+    /* Set face_index to 0.  */
+    *face_instance_index = 0;
+
+    /* error = FT_THROW( Unimplemented_Feature ); */
     /* DEBUG - Remove later */
     FT_TRACE2(( "Reached end without errors.\n" ));
     goto Exit;
@@ -1658,6 +1957,7 @@
 #undef WRITE_ULONG
 #undef WRITE_SHORT
 #undef WRITE_SFNT_BUF
+#undef WRITE_SFNT_BUF_AT
 
 #undef N_CONTOUR_STREAM
 #undef N_POINTS_STREAM
--- a/src/sfnt/sfwoff2.h
+++ b/src/sfnt/sfwoff2.h
@@ -64,7 +64,7 @@
   FT_LOCAL( FT_Error )
   woff2_open_font( FT_Stream  stream,
                    TT_Face    face,
-                   FT_Int     face_index );
+                   FT_Int*    face_index );
 
 
 FT_END_HEADER