Commit 81cf5326d59282265ccc0911050005a4b5d20a99

Nikhil Ramakrishnan 2019-07-06T18:05:18

[woff2] Copy un-transformed tables to sfnt stream. Copy un-transformed tables to the sfnt stream. * src/sfnt/sfwoff2.c: (WRITE_SFNT_BUF): New macro. (write_buf): New function. Extend memory of `dst' buffer and copy bytes from `src'. (compute_ULong_sum): New function. Calculate checksum of table. (reconstruct_font): Change `FT_Byte* sfnt' to `FT_Byte** sfnt_bytes'. This has been done because we reallocate memory to `sfnt' multiple times, which may change the pointer value of `sfnt'. This new pointer must be propogated back to the caller. Same reason for using a double pointer in `write_buf'. * src/sfnt/woff2tags.h (WOFF2_DEFAULT_MAX_SIZE): New macro used for overflow checking.

diff --git a/ChangeLog b/ChangeLog
index 2baee36..01bde59 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
 2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
 
+	[woff2] Copy un-transformed tables to sfnt stream.
+
+	Copy un-transformed tables to the sfnt stream.
+
+	* src/sfnt/sfwoff2.c: (WRITE_SFNT_BUF): New macro.
+	(write_buf): New function.  Extend memory of `dst' buffer and copy
+	bytes from `src'.
+	(compute_ULong_sum): New function.  Calculate checksum of table.
+	(reconstruct_font): Change `FT_Byte* sfnt' to `FT_Byte**
+	sfnt_bytes'.  This has been done because we reallocate memory to
+	`sfnt' multiple times, which may change the pointer value of `sfnt'.
+	This new pointer must be propogated back to the caller.  Same reason
+	for using a double pointer in `write_buf'.
+
+	* src/sfnt/woff2tags.h (WOFF2_DEFAULT_MAX_SIZE): New macro used for
+	overflow checking.
+
+2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
+
 	[woff2] Create stream for uncompressed buffer.
 
 	Uncompressed buffer is now an `FT_Stream'.
diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c
index a44cd6f..cc6a4d1 100644
--- a/src/sfnt/sfwoff2.c
+++ b/src/sfnt/sfwoff2.c
@@ -64,6 +64,8 @@
                                              \
           } while ( 0 )
 
+#define WRITE_SFNT_BUF( buf, s ) \
+          write_buf( &sfnt, &dest_offset, buf, s, memory )
 
   static void
   stream_close( FT_Stream  stream )
@@ -182,6 +184,41 @@
   }
 
 
+  static FT_Error
+  write_buf( FT_Byte**  dst_bytes,
+             FT_ULong*  offset,
+             FT_Byte*   src,
+             FT_ULong   size,
+             FT_Memory  memory )
+  {
+    FT_Error  error = FT_Err_Ok;
+    /* We are reallocating memory for `dst', so its pointer may change. */
+    FT_Byte*  dst   = *dst_bytes;
+
+    /* Check if we are within limits. */
+    if( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE  )
+      return FT_THROW( Array_Too_Large );
+
+    /* 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;
+
+    /* Copy data. */
+    ft_memcpy( dst + *offset, src, size );
+
+    *offset += size;
+    /* Set pointer of `dst' to its correct value. */
+    *dst_bytes = dst;
+
+  Exit:
+    return error;
+  }
+
+
   static FT_Offset
   CollectionHeaderSize( FT_ULong header_version,
                         FT_UShort num_fonts )
@@ -216,6 +253,32 @@
     return offset;
   }
 
+  static FT_Long
+  compute_ULong_sum( FT_Byte*  buf,
+                     FT_ULong  size )
+  {
+    FT_ULong  checksum     = 0;
+    FT_ULong  aligned_size = size & ~3;
+    FT_ULong  i;
+    FT_ULong  v;
+
+    for( i = 0; i < aligned_size; i += 4 )
+    {
+      checksum += ( buf[i] << 24 ) | ( buf[i+1] << 16 ) |
+                  ( buf[i+2] << 8 ) | ( buf[i+3] << 0 );
+    }
+
+    /* If size is not aligned to 4, treat as if it is padded with 0s */
+    if( size != aligned_size )
+    {
+      v = 0;
+      for( i = aligned_size ; i < size; ++i )
+        v |= buf[i] << ( 24 - 8 * ( i & 3 ) );
+      checksum += v;
+    }
+    return checksum;
+  }
+
 
   static FT_Error
   woff2_uncompress( FT_Byte*        dst,
@@ -293,15 +356,17 @@
                     FT_ULong       transformed_buf_size,
                     WOFF2_Table*   indices,
                     WOFF2_Header   woff2,
-                    FT_Byte*       sfnt,
+                    FT_Byte**      sfnt_bytes,
                     FT_Memory      memory )
   {
     FT_Error   error  = FT_Err_Ok;
     FT_Stream  stream = NULL;
+    FT_Byte*   buf_cursor = NULL;
+    /* We are reallocating memory for `sfnt', so its pointer may change. */
+    FT_Byte*   sfnt       = *sfnt_bytes;
 
-    /* We're writing only one face per call, so initial offset is fixed. */
-    FT_ULong   dst_offset  = 12;
     FT_UShort  num_tables  = woff2->num_tables;
+    FT_ULong   dest_offset = 12 + num_tables * 16UL;
 
     FT_ULong  checksum      = 0;
     FT_ULong  loca_checksum = 0;
@@ -333,7 +398,6 @@
         }
     }
 
-    FT_UNUSED( dst_offset );
     FT_UNUSED( loca_checksum );
     FT_UNUSED( checksum );
 
@@ -351,12 +415,14 @@
       WOFF2_TableRec  table = *( indices[nn] );
 
       /* DEBUG - Remove later */
-      FT_TRACE2(( "Seeking to %d with table size %d.\n", table.src_offset, table.src_length ));
+      FT_TRACE2(( "Seeking to %d with table size %d.\n",
+                  table.src_offset, table.src_length ));
       FT_TRACE2(( "Table tag: %c%c%c%c.\n",
             (FT_Char)( table.Tag >> 24 ),
             (FT_Char)( table.Tag >> 16 ),
             (FT_Char)( table.Tag >> 8  ),
             (FT_Char)( table.Tag       ) ));
+
       if ( FT_STREAM_SEEK( table.src_offset ) )
         return FT_THROW( Invalid_Table );
 
@@ -370,6 +436,7 @@
           return FT_THROW( Invalid_Table );
       }
 
+      checksum = 0;
       if( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM )
       {
         /* Check if `head' is atleast 12 bytes. */
@@ -377,12 +444,30 @@
         {
           if( table.src_length < 12 )
             return FT_THROW( Invalid_Table );
+          buf_cursor = transformed_buf + table.src_offset + 8;
+          WRITE_ULONG( buf_cursor, 0 );
         }
+        table.dst_offset = dest_offset;
+        checksum = compute_ULong_sum( transformed_buf + table.src_offset,
+                                     table.src_length );
+        /* DEBUG - Remove later */
+        FT_TRACE2(( "Checksum = %u\n", checksum ));
+
+        if( WRITE_SFNT_BUF( transformed_buf + table.src_offset,
+                            table.src_length ) )
+          return FT_THROW( Invalid_Table );
+      }
+      else{
+        /* DEBUG - Remove later */
+        FT_TRACE2(( "This table has xform.\n" ));
+
+        /* TODO reconstruct transformed font tables! */
       }
 
     }
 
-    /* TODO reconstruct the font tables! */
+    /* Set pointer of sfnt stream to its correct value. */
+    *sfnt_bytes = sfnt;
     return FT_Err_Ok;
   }
 
@@ -793,7 +878,7 @@
 
     /* TODO Write table entries. */
     reconstruct_font( uncompressed_buf, woff2.uncompressed_size,
-                      indices, &woff2, sfnt, memory );
+                      indices, &woff2, &sfnt, memory );
 
     error = FT_THROW( Unimplemented_Feature );
     /* DEBUG - Remove later */
@@ -821,6 +906,7 @@
 #undef ROUND4
 #undef WRITE_USHORT
 #undef WRITE_ULONG
+#undef WRITE_SFNT_BUF
 
 
 /* END */
diff --git a/src/sfnt/woff2tags.h b/src/sfnt/woff2tags.h
index 6579b85..422567d 100644
--- a/src/sfnt/woff2tags.h
+++ b/src/sfnt/woff2tags.h
@@ -33,6 +33,9 @@ FT_BEGIN_HEADER
 #define WOFF2_SFNT_HEADER_SIZE  12
 #define WOFF2_SFNT_ENTRY_SIZE   16
 
+  /* Suggested max size for output. */
+#define WOFF2_DEFAULT_MAX_SIZE  30 * 1024 * 1024
+
   FT_LOCAL( FT_ULong )
   woff2_known_tags( FT_Byte  index );