Commit 2fa573c1b038a32b7c6f5c76477f9b66a47cc425

Nikhil Ramakrishnan 2019-06-12T00:21:20

[sfnt] Read WOFF 2 header. Check for WOFF2 tag, call `woff2_open_font', and implement it to read header according to specification. * include/freetype/internal/fttrace.h: Add `sfwoff2.c'. * src/sfnt/rules.mk (SFNT_DRV_SRC): Add `sfwoff2.c'. * src/sfnt/sfnt.c: Include `sfwoff2.c'. * src/sfnt/sfobjs.c (sfnt_open_font): Check for `wOF2' tag and call `woff2_open_font'. * src/sfnt/sfwoff2.c, src/sfnt/sfwoff2.h: New files.

diff --git a/ChangeLog b/ChangeLog
index 025c9c4..c1d81ee 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
 
+	[sfnt] Read WOFF 2 header.
+
+	Check for WOFF2 tag, call `woff2_open_font', and implement it to read
+	header according to specification.
+
+	* include/freetype/internal/fttrace.h: Add `sfwoff2.c'.
+
+	* src/sfnt/rules.mk (SFNT_DRV_SRC): Add `sfwoff2.c'.
+
+	* src/sfnt/sfnt.c: Include `sfwoff2.c'.
+
+	* src/sfnt/sfobjs.c (sfnt_open_font): Check for `wOF2' tag and call
+	`woff2_open_font'.
+
+	* src/sfnt/sfwoff2.c, src/sfnt/sfwoff2.h: New files.
+
+2019-08-27  Nikhil Ramakrishnan  <ramakrishnan.nikhil@gmail.com>
+
 	Add structures for WOFF2.
 
 	Add structures and macro for WOFF 2 header and table directory.
diff --git a/include/freetype/internal/fttrace.h b/include/freetype/internal/fttrace.h
index f5f9598..77e0e41 100644
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -49,6 +49,7 @@ FT_TRACE_DEF( cache )     /* cache sub-system        (ftcache.c, etc.) */
 FT_TRACE_DEF( sfdriver )  /* SFNT font driver        (sfdriver.c) */
 FT_TRACE_DEF( sfobjs )    /* SFNT object handler     (sfobjs.c)   */
 FT_TRACE_DEF( sfwoff )    /* WOFF format handler     (sfwoff.c)   */
+FT_TRACE_DEF( sfwoff2 )   /* WOFF2 format handler    (sfwoff2.c)  */
 FT_TRACE_DEF( ttbdf )     /* TrueType embedded BDF   (ttbdf.c)    */
 FT_TRACE_DEF( ttcmap )    /* charmap handler         (ttcmap.c)   */
 FT_TRACE_DEF( ttcolr )    /* glyph layer table       (ttcolr.c)   */
diff --git a/src/sfnt/rules.mk b/src/sfnt/rules.mk
index ee3314e..a77b8dd 100644
--- a/src/sfnt/rules.mk
+++ b/src/sfnt/rules.mk
@@ -32,6 +32,7 @@ SFNT_DRV_SRC := $(SFNT_DIR)/pngshim.c  \
                 $(SFNT_DIR)/sfdriver.c \
                 $(SFNT_DIR)/sfobjs.c   \
                 $(SFNT_DIR)/sfwoff.c   \
+                $(SFNT_DIR)/sfwoff2.c  \
                 $(SFNT_DIR)/ttbdf.c    \
                 $(SFNT_DIR)/ttcmap.c   \
                 $(SFNT_DIR)/ttcolr.c   \
diff --git a/src/sfnt/sfnt.c b/src/sfnt/sfnt.c
index b4faf34..9fed618 100644
--- a/src/sfnt/sfnt.c
+++ b/src/sfnt/sfnt.c
@@ -23,6 +23,7 @@
 #include "sfdriver.c"
 #include "sfobjs.c"
 #include "sfwoff.c"
+#include "sfwoff2.c"
 #include "ttbdf.c"
 #include "ttcmap.c"
 #include "ttcolr.c"
diff --git a/src/sfnt/sfobjs.c b/src/sfnt/sfobjs.c
index 6edf3ae..b5a6523 100644
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -22,6 +22,7 @@
 #include "ttcmap.h"
 #include "ttkern.h"
 #include "sfwoff.h"
+#include "sfwoff2.h"
 #include FT_INTERNAL_SFNT_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_TRUETYPE_IDS_H
@@ -385,6 +386,22 @@
       goto retry;
     }
 
+    if ( tag == TTAG_wOF2 )
+    {
+      FT_TRACE2(( "sfnt_open_font: file is a WOFF2; synthesizing SFNT\n" ));
+
+      if ( FT_STREAM_SEEK( offset ) )
+        return error;
+
+      error = woff2_open_font( stream, face );
+      if ( error )
+        return error;
+
+      /* Swap out stream and retry! */
+      stream = face->root.stream;
+      goto retry;
+    }
+
     if ( tag != 0x00010000UL &&
          tag != TTAG_ttcf    &&
          tag != TTAG_OTTO    &&
diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c
new file mode 100644
index 0000000..e205b66
--- /dev/null
+++ b/src/sfnt/sfwoff2.c
@@ -0,0 +1,169 @@
+/****************************************************************************
+ *
+ * sfwoff2.c
+ *
+ *   WOFF2 format management (base).
+ *
+ * Copyright (C) 2019 by
+ * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+#include <ft2build.h>
+#include "sfwoff2.h"
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+
+  /**************************************************************************
+   *
+   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
+   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
+   * messages during execution.
+   */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  sfwoff2
+
+
+  static FT_Error
+  ReadBase128( FT_Stream  stream,
+               FT_ULong*  value )
+  {
+    FT_ULong  result = 0;
+    FT_Int    i;
+    FT_Byte   code;
+    FT_Byte*  p = stream->cursor;
+
+    for ( i = 0; i < 5; ++i ) {
+      code = 0;
+      code = FT_NEXT_BYTE( p );
+
+      /* Leading zeros are invalid. */
+      if ( i == 0 && code == 0x80 ) {
+        return FT_THROW( Invalid_Table );
+      }
+
+      /* If any of top seven bits are set then we're about to overflow. */
+      if ( result & 0xfe000000 ){
+        return FT_THROW( Invalid_Table );
+      }
+
+      result = ( result << 7 ) | ( code & 0x7f );
+
+      /* Spin until most significant bit of data byte is false. */
+      if ( (code & 0x80) == 0 ) {
+        *value = result;
+        return FT_Err_Ok;
+      }
+    }
+    /* Make sure not to exceed the size bound. */
+    return FT_THROW( Invalid_Table );
+  }
+
+
+  /* Replace `face->root.stream' with a stream containing the extracted */
+  /* SFNT of a WOFF2 font.                                              */
+
+  FT_LOCAL_DEF( FT_Error )
+  woff2_open_font( FT_Stream  stream,
+                   TT_Face    face )
+  {
+    FT_Memory        memory = stream->memory;
+    FT_Error         error  = FT_Err_Ok;
+    FT_Byte*         p      = stream->cursor;
+    FT_Byte*         limit  = stream->limit;
+
+    WOFF2_HeaderRec  woff2;
+    WOFF2_Table      tables  = NULL;
+    WOFF2_Table*     indices = NULL;
+
+    static const FT_Frame_Field  woff2_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  WOFF2_HeaderRec
+
+      FT_FRAME_START( 48 ),
+        FT_FRAME_ULONG ( signature ),
+        FT_FRAME_ULONG ( flavor ),
+        FT_FRAME_ULONG ( length ),
+        FT_FRAME_USHORT( num_tables ),
+        FT_FRAME_SKIP_BYTES( 2 + 4 ),
+        FT_FRAME_ULONG ( totalCompressedSize ),
+        FT_FRAME_SKIP_BYTES( 2 * 2 ),
+        FT_FRAME_ULONG ( metaOffset ),
+        FT_FRAME_ULONG ( metaLength ),
+        FT_FRAME_ULONG ( metaOrigLength ),
+        FT_FRAME_ULONG ( privOffset ),
+        FT_FRAME_ULONG ( privLength ),
+      FT_FRAME_END
+    };
+
+    FT_UNUSED( p );
+    FT_UNUSED( limit );
+    FT_UNUSED( tables );
+    FT_UNUSED( indices );
+    FT_UNUSED( memory );
+
+    /* DEBUG - Remove later */
+    FT_TRACE2(("woff2_open_font: Received Data.\n"));
+
+    FT_ASSERT( stream == face->root.stream );
+    FT_ASSERT( FT_STREAM_POS() == 0 );
+
+    /* Read WOFF2 Header. */
+    if ( FT_STREAM_READ_FIELDS( woff2_header_fields, &woff2 ) )
+      return error;
+
+    /* DEBUG - Remove later. */
+    FT_TRACE2(("signature  -> 0x%X\n", woff2.signature));
+    FT_TRACE2(("flavor     -> 0x%X\n", woff2.flavor));
+    FT_TRACE2(("length     -> %lu\n", woff2.length));
+    FT_TRACE2(("num_tables -> %hu\n", woff2.num_tables));
+    FT_TRACE2(("metaOffset -> %hu\n", woff2.metaOffset));
+    FT_TRACE2(("metaLength -> %hu\n", woff2.metaLength));
+    FT_TRACE2(("privOffset -> %hu\n", woff2.privOffset));
+    FT_TRACE2(("privLength -> %hu\n", woff2.privLength));
+
+    /* Make sure we don't recurse back here. */
+    if ( woff2.flavor == TTAG_wOF2 )
+      return FT_THROW( Invalid_Table );
+
+    /* Miscellaneous checks. */
+    if ( woff2.length != stream->size                               ||
+         woff2.num_tables == 0                                      ||
+         48 + woff2.num_tables * 20UL >= woff2.length               ||
+         ( woff2.metaOffset == 0 && ( woff2.metaLength != 0     ||
+                                      woff2.metaOrigLength != 0 ) ) ||
+         ( woff2.metaLength != 0 && woff2.metaOrigLength == 0 )     ||
+         ( woff2.metaOffset >= woff2.length )                       ||
+         ( woff2.length - woff2.metaOffset < woff2.metaLength )     ||
+         ( woff2.privOffset == 0 && woff2.privLength != 0 )         ||
+         ( woff2.privOffset >= woff2.length )                       ||
+         ( woff2.length - woff2.privOffset < woff2.privLength )     )
+    {
+      FT_ERROR(( "woff_font_open: invalid WOFF2 header\n" ));
+      return FT_THROW( Invalid_Table );
+    }
+    /* DEBUG - Remove later. */
+    else{
+      FT_TRACE2(("WOFF2 Header is valid.\n"));
+    }
+
+    /* TODO Read table directory. */
+
+    error = FT_THROW( Unimplemented_Feature );
+    goto Exit;
+
+  Exit:
+    return error;
+  }
+
+
+/* END */
diff --git a/src/sfnt/sfwoff2.h b/src/sfnt/sfwoff2.h
new file mode 100644
index 0000000..5c3cc3d
--- /dev/null
+++ b/src/sfnt/sfwoff2.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+ *
+ * sfwoff2.h
+ *
+ *   WOFFF2 format management (specification).
+ *
+ * Copyright (C) 2019 by
+ * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg.
+ *
+ * This file is part of the FreeType project, and may only be used,
+ * modified, and distributed under the terms of the FreeType project
+ * license, LICENSE.TXT.  By continuing to use, modify, or distribute
+ * this file you indicate that you have read the license and
+ * understand and accept it fully.
+ *
+ */
+
+
+#ifndef SFWOFF2_H_
+#define SFWOFF2_H_
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  woff2_open_font( FT_Stream  stream,
+                   TT_Face    face );
+
+
+FT_END_HEADER
+
+#endif /* SFWOFF2_H_ */
+
+
+/* END */