[sfnt] Separate WOFF sources and headers.
Move WOFF sources and headers to separate files. * include/freetype/internal/wofftypes.h, src/sfnt/sfwoff.c, src/sfnt/sfwoff.h: New files. * include/freetype/internal/fttrace.h: Register `sfwoff.c'. * include/freetype/internal/internal.h: Define FT_INTERNAL_WOFF_TYPES_H. * include/freetype/internal/sfnt.h: Include FT_INTERNAL_WOFF_TYPES_H. * include/freetype/internal/tttypes.h: Move out WOFF structures. * src/sfnt/rules.mk: Add `sfwoff.c'. * src/sfnt/sfnt.c: Include `sfwoff.c'. * src/sfnt/sfobjs.c: Include `sfwoff.h', move out WOFF sources.
This commit is contained in:
parent
f0de218ced
commit
7b275a5af1
24
ChangeLog
24
ChangeLog
|
@ -1,3 +1,27 @@
|
||||||
|
2019-05-30 Nikhil Ramakrishnan <ramakrishnan.nikhil@gmail.com>
|
||||||
|
|
||||||
|
[sfnt] Separate WOFF sources and headers.
|
||||||
|
|
||||||
|
Move WOFF sources and headers to separate files.
|
||||||
|
|
||||||
|
* include/freetype/internal/wofftypes.h, src/sfnt/sfwoff.c,
|
||||||
|
src/sfnt/sfwoff.h: New files.
|
||||||
|
|
||||||
|
* include/freetype/internal/fttrace.h: Register `sfwoff.c'.
|
||||||
|
|
||||||
|
* include/freetype/internal/internal.h: Define
|
||||||
|
FT_INTERNAL_WOFF_TYPES_H.
|
||||||
|
|
||||||
|
* include/freetype/internal/sfnt.h: Include FT_INTERNAL_WOFF_TYPES_H.
|
||||||
|
|
||||||
|
* include/freetype/internal/tttypes.h: Move out WOFF structures.
|
||||||
|
|
||||||
|
* src/sfnt/rules.mk: Add `sfwoff.c'.
|
||||||
|
|
||||||
|
* src/sfnt/sfnt.c: Include `sfwoff.c'.
|
||||||
|
|
||||||
|
* src/sfnt/sfobjs.c: Include `sfwoff.h', move out WOFF sources.
|
||||||
|
|
||||||
2019-05-30 Werner Lemberg <wl@gnu.org>
|
2019-05-30 Werner Lemberg <wl@gnu.org>
|
||||||
|
|
||||||
[base] Fix `make multi'.
|
[base] Fix `make multi'.
|
||||||
|
|
|
@ -48,6 +48,7 @@ FT_TRACE_DEF( cache ) /* cache sub-system (ftcache.c, etc.) */
|
||||||
/* SFNT driver components */
|
/* SFNT driver components */
|
||||||
FT_TRACE_DEF( sfdriver ) /* SFNT font driver (sfdriver.c) */
|
FT_TRACE_DEF( sfdriver ) /* SFNT font driver (sfdriver.c) */
|
||||||
FT_TRACE_DEF( sfobjs ) /* SFNT object handler (sfobjs.c) */
|
FT_TRACE_DEF( sfobjs ) /* SFNT object handler (sfobjs.c) */
|
||||||
|
FT_TRACE_DEF( sfwoff ) /* WOFF format handler (sfwoff.c) */
|
||||||
FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */
|
FT_TRACE_DEF( ttbdf ) /* TrueType embedded BDF (ttbdf.c) */
|
||||||
FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */
|
FT_TRACE_DEF( ttcmap ) /* charmap handler (ttcmap.c) */
|
||||||
FT_TRACE_DEF( ttcolr ) /* glyph layer table (ttcolr.c) */
|
FT_TRACE_DEF( ttcolr ) /* glyph layer table (ttcolr.c) */
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h>
|
#define FT_INTERNAL_TRUETYPE_TYPES_H <freetype/internal/tttypes.h>
|
||||||
#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h>
|
#define FT_INTERNAL_TYPE1_TYPES_H <freetype/internal/t1types.h>
|
||||||
|
#define FT_INTERNAL_WOFF_TYPES_H <freetype/internal/wofftypes.h>
|
||||||
|
|
||||||
#define FT_INTERNAL_POSTSCRIPT_AUX_H <freetype/internal/psaux.h>
|
#define FT_INTERNAL_POSTSCRIPT_AUX_H <freetype/internal/psaux.h>
|
||||||
#define FT_INTERNAL_POSTSCRIPT_HINTS_H <freetype/internal/pshints.h>
|
#define FT_INTERNAL_POSTSCRIPT_HINTS_H <freetype/internal/pshints.h>
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_INTERNAL_DRIVER_H
|
#include FT_INTERNAL_DRIVER_H
|
||||||
#include FT_INTERNAL_TRUETYPE_TYPES_H
|
#include FT_INTERNAL_TRUETYPE_TYPES_H
|
||||||
|
#include FT_INTERNAL_WOFF_TYPES_H
|
||||||
|
|
||||||
|
|
||||||
FT_BEGIN_HEADER
|
FT_BEGIN_HEADER
|
||||||
|
|
|
@ -150,81 +150,6 @@ FT_BEGIN_HEADER
|
||||||
} TT_TableRec, *TT_Table;
|
} TT_TableRec, *TT_Table;
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
*
|
|
||||||
* @struct:
|
|
||||||
* WOFF_HeaderRec
|
|
||||||
*
|
|
||||||
* @description:
|
|
||||||
* WOFF file format header.
|
|
||||||
*
|
|
||||||
* @fields:
|
|
||||||
* See
|
|
||||||
*
|
|
||||||
* https://www.w3.org/TR/WOFF/#WOFFHeader
|
|
||||||
*/
|
|
||||||
typedef struct WOFF_HeaderRec_
|
|
||||||
{
|
|
||||||
FT_ULong signature;
|
|
||||||
FT_ULong flavor;
|
|
||||||
FT_ULong length;
|
|
||||||
FT_UShort num_tables;
|
|
||||||
FT_UShort reserved;
|
|
||||||
FT_ULong totalSfntSize;
|
|
||||||
FT_UShort majorVersion;
|
|
||||||
FT_UShort minorVersion;
|
|
||||||
FT_ULong metaOffset;
|
|
||||||
FT_ULong metaLength;
|
|
||||||
FT_ULong metaOrigLength;
|
|
||||||
FT_ULong privOffset;
|
|
||||||
FT_ULong privLength;
|
|
||||||
|
|
||||||
} WOFF_HeaderRec, *WOFF_Header;
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
*
|
|
||||||
* @struct:
|
|
||||||
* WOFF_TableRec
|
|
||||||
*
|
|
||||||
* @description:
|
|
||||||
* This structure describes a given table of a WOFF font.
|
|
||||||
*
|
|
||||||
* @fields:
|
|
||||||
* Tag ::
|
|
||||||
* A four-bytes tag describing the table.
|
|
||||||
*
|
|
||||||
* Offset ::
|
|
||||||
* The offset of the table from the start of the WOFF font in its
|
|
||||||
* resource.
|
|
||||||
*
|
|
||||||
* CompLength ::
|
|
||||||
* Compressed table length (in bytes).
|
|
||||||
*
|
|
||||||
* OrigLength ::
|
|
||||||
* Uncompressed table length (in bytes).
|
|
||||||
*
|
|
||||||
* CheckSum ::
|
|
||||||
* The table checksum. This value can be ignored.
|
|
||||||
*
|
|
||||||
* OrigOffset ::
|
|
||||||
* The uncompressed table file offset. This value gets computed while
|
|
||||||
* constructing the (uncompressed) SFNT header. It is not contained in
|
|
||||||
* the WOFF file.
|
|
||||||
*/
|
|
||||||
typedef struct WOFF_TableRec_
|
|
||||||
{
|
|
||||||
FT_ULong Tag; /* table ID */
|
|
||||||
FT_ULong Offset; /* table file offset */
|
|
||||||
FT_ULong CompLength; /* compressed table length */
|
|
||||||
FT_ULong OrigLength; /* uncompressed table length */
|
|
||||||
FT_ULong CheckSum; /* uncompressed checksum */
|
|
||||||
|
|
||||||
FT_ULong OrigOffset; /* uncompressed table file offset */
|
|
||||||
/* (not in the WOFF file) */
|
|
||||||
} WOFF_TableRec, *WOFF_Table;
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* @struct:
|
* @struct:
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* wofftypes.h
|
||||||
|
*
|
||||||
|
* Basic WOFF/WOFF2 type definitions and interface (specification
|
||||||
|
* only).
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996-2019 by
|
||||||
|
* 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 WOFFTYPES_H_
|
||||||
|
#define WOFFTYPES_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_TRUETYPE_TABLES_H
|
||||||
|
#include FT_INTERNAL_OBJECTS_H
|
||||||
|
|
||||||
|
|
||||||
|
FT_BEGIN_HEADER
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* @struct:
|
||||||
|
* WOFF_HeaderRec
|
||||||
|
*
|
||||||
|
* @description:
|
||||||
|
* WOFF file format header.
|
||||||
|
*
|
||||||
|
* @fields:
|
||||||
|
* See
|
||||||
|
*
|
||||||
|
* https://www.w3.org/TR/WOFF/#WOFFHeader
|
||||||
|
*/
|
||||||
|
typedef struct WOFF_HeaderRec_
|
||||||
|
{
|
||||||
|
FT_ULong signature;
|
||||||
|
FT_ULong flavor;
|
||||||
|
FT_ULong length;
|
||||||
|
FT_UShort num_tables;
|
||||||
|
FT_UShort reserved;
|
||||||
|
FT_ULong totalSfntSize;
|
||||||
|
FT_UShort majorVersion;
|
||||||
|
FT_UShort minorVersion;
|
||||||
|
FT_ULong metaOffset;
|
||||||
|
FT_ULong metaLength;
|
||||||
|
FT_ULong metaOrigLength;
|
||||||
|
FT_ULong privOffset;
|
||||||
|
FT_ULong privLength;
|
||||||
|
|
||||||
|
} WOFF_HeaderRec, *WOFF_Header;
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* @struct:
|
||||||
|
* WOFF_TableRec
|
||||||
|
*
|
||||||
|
* @description:
|
||||||
|
* This structure describes a given table of a WOFF font.
|
||||||
|
*
|
||||||
|
* @fields:
|
||||||
|
* Tag ::
|
||||||
|
* A four-bytes tag describing the table.
|
||||||
|
*
|
||||||
|
* Offset ::
|
||||||
|
* The offset of the table from the start of the WOFF font in its
|
||||||
|
* resource.
|
||||||
|
*
|
||||||
|
* CompLength ::
|
||||||
|
* Compressed table length (in bytes).
|
||||||
|
*
|
||||||
|
* OrigLength ::
|
||||||
|
* Uncompressed table length (in bytes).
|
||||||
|
*
|
||||||
|
* CheckSum ::
|
||||||
|
* The table checksum. This value can be ignored.
|
||||||
|
*
|
||||||
|
* OrigOffset ::
|
||||||
|
* The uncompressed table file offset. This value gets computed while
|
||||||
|
* constructing the (uncompressed) SFNT header. It is not contained in
|
||||||
|
* the WOFF file.
|
||||||
|
*/
|
||||||
|
typedef struct WOFF_TableRec_
|
||||||
|
{
|
||||||
|
FT_ULong Tag; /* table ID */
|
||||||
|
FT_ULong Offset; /* table file offset */
|
||||||
|
FT_ULong CompLength; /* compressed table length */
|
||||||
|
FT_ULong OrigLength; /* uncompressed table length */
|
||||||
|
FT_ULong CheckSum; /* uncompressed checksum */
|
||||||
|
|
||||||
|
FT_ULong OrigOffset; /* uncompressed table file offset */
|
||||||
|
/* (not in the WOFF file) */
|
||||||
|
} WOFF_TableRec, *WOFF_Table;
|
||||||
|
|
||||||
|
|
||||||
|
FT_END_HEADER
|
||||||
|
|
||||||
|
#endif /* WOFFTYPES_H_ */
|
||||||
|
|
||||||
|
|
||||||
|
/* END */
|
|
@ -31,6 +31,7 @@ SFNT_COMPILE := $(CC) $(ANSIFLAGS) \
|
||||||
SFNT_DRV_SRC := $(SFNT_DIR)/pngshim.c \
|
SFNT_DRV_SRC := $(SFNT_DIR)/pngshim.c \
|
||||||
$(SFNT_DIR)/sfdriver.c \
|
$(SFNT_DIR)/sfdriver.c \
|
||||||
$(SFNT_DIR)/sfobjs.c \
|
$(SFNT_DIR)/sfobjs.c \
|
||||||
|
$(SFNT_DIR)/sfwoff.c \
|
||||||
$(SFNT_DIR)/ttbdf.c \
|
$(SFNT_DIR)/ttbdf.c \
|
||||||
$(SFNT_DIR)/ttcmap.c \
|
$(SFNT_DIR)/ttcmap.c \
|
||||||
$(SFNT_DIR)/ttcolr.c \
|
$(SFNT_DIR)/ttcolr.c \
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "pngshim.c"
|
#include "pngshim.c"
|
||||||
#include "sfdriver.c"
|
#include "sfdriver.c"
|
||||||
#include "sfobjs.c"
|
#include "sfobjs.c"
|
||||||
|
#include "sfwoff.c"
|
||||||
#include "ttbdf.c"
|
#include "ttbdf.c"
|
||||||
#include "ttcmap.c"
|
#include "ttcmap.c"
|
||||||
#include "ttcolr.c"
|
#include "ttcolr.c"
|
||||||
|
|
|
@ -21,13 +21,13 @@
|
||||||
#include "ttload.h"
|
#include "ttload.h"
|
||||||
#include "ttcmap.h"
|
#include "ttcmap.h"
|
||||||
#include "ttkern.h"
|
#include "ttkern.h"
|
||||||
|
#include "sfwoff.h"
|
||||||
#include FT_INTERNAL_SFNT_H
|
#include FT_INTERNAL_SFNT_H
|
||||||
#include FT_INTERNAL_DEBUG_H
|
#include FT_INTERNAL_DEBUG_H
|
||||||
#include FT_TRUETYPE_IDS_H
|
#include FT_TRUETYPE_IDS_H
|
||||||
#include FT_TRUETYPE_TAGS_H
|
#include FT_TRUETYPE_TAGS_H
|
||||||
#include FT_SERVICE_POSTSCRIPT_CMAPS_H
|
#include FT_SERVICE_POSTSCRIPT_CMAPS_H
|
||||||
#include FT_SFNT_NAMES_H
|
#include FT_SFNT_NAMES_H
|
||||||
#include FT_GZIP_H
|
|
||||||
|
|
||||||
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||||
#include FT_SERVICE_MULTIPLE_MASTERS_H
|
#include FT_SERVICE_MULTIPLE_MASTERS_H
|
||||||
|
@ -337,403 +337,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define WRITE_USHORT( p, v ) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
*(p)++ = (FT_Byte)( (v) >> 8 ); \
|
|
||||||
*(p)++ = (FT_Byte)( (v) >> 0 ); \
|
|
||||||
\
|
|
||||||
} while ( 0 )
|
|
||||||
|
|
||||||
#define WRITE_ULONG( p, v ) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
*(p)++ = (FT_Byte)( (v) >> 24 ); \
|
|
||||||
*(p)++ = (FT_Byte)( (v) >> 16 ); \
|
|
||||||
*(p)++ = (FT_Byte)( (v) >> 8 ); \
|
|
||||||
*(p)++ = (FT_Byte)( (v) >> 0 ); \
|
|
||||||
\
|
|
||||||
} while ( 0 )
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
sfnt_stream_close( FT_Stream stream )
|
|
||||||
{
|
|
||||||
FT_Memory memory = stream->memory;
|
|
||||||
|
|
||||||
|
|
||||||
FT_FREE( stream->base );
|
|
||||||
|
|
||||||
stream->size = 0;
|
|
||||||
stream->base = NULL;
|
|
||||||
stream->close = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FT_CALLBACK_DEF( int )
|
|
||||||
compare_offsets( const void* a,
|
|
||||||
const void* b )
|
|
||||||
{
|
|
||||||
WOFF_Table table1 = *(WOFF_Table*)a;
|
|
||||||
WOFF_Table table2 = *(WOFF_Table*)b;
|
|
||||||
|
|
||||||
FT_ULong offset1 = table1->Offset;
|
|
||||||
FT_ULong offset2 = table2->Offset;
|
|
||||||
|
|
||||||
|
|
||||||
if ( offset1 > offset2 )
|
|
||||||
return 1;
|
|
||||||
else if ( offset1 < offset2 )
|
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Replace `face->root.stream' with a stream containing the extracted */
|
|
||||||
/* SFNT of a WOFF font. */
|
|
||||||
|
|
||||||
static FT_Error
|
|
||||||
woff_open_font( FT_Stream stream,
|
|
||||||
TT_Face face )
|
|
||||||
{
|
|
||||||
FT_Memory memory = stream->memory;
|
|
||||||
FT_Error error = FT_Err_Ok;
|
|
||||||
|
|
||||||
WOFF_HeaderRec woff;
|
|
||||||
WOFF_Table tables = NULL;
|
|
||||||
WOFF_Table* indices = NULL;
|
|
||||||
|
|
||||||
FT_ULong woff_offset;
|
|
||||||
|
|
||||||
FT_Byte* sfnt = NULL;
|
|
||||||
FT_Stream sfnt_stream = NULL;
|
|
||||||
|
|
||||||
FT_Byte* sfnt_header;
|
|
||||||
FT_ULong sfnt_offset;
|
|
||||||
|
|
||||||
FT_Int nn;
|
|
||||||
FT_ULong old_tag = 0;
|
|
||||||
|
|
||||||
static const FT_Frame_Field woff_header_fields[] =
|
|
||||||
{
|
|
||||||
#undef FT_STRUCTURE
|
|
||||||
#define FT_STRUCTURE WOFF_HeaderRec
|
|
||||||
|
|
||||||
FT_FRAME_START( 44 ),
|
|
||||||
FT_FRAME_ULONG ( signature ),
|
|
||||||
FT_FRAME_ULONG ( flavor ),
|
|
||||||
FT_FRAME_ULONG ( length ),
|
|
||||||
FT_FRAME_USHORT( num_tables ),
|
|
||||||
FT_FRAME_USHORT( reserved ),
|
|
||||||
FT_FRAME_ULONG ( totalSfntSize ),
|
|
||||||
FT_FRAME_USHORT( majorVersion ),
|
|
||||||
FT_FRAME_USHORT( minorVersion ),
|
|
||||||
FT_FRAME_ULONG ( metaOffset ),
|
|
||||||
FT_FRAME_ULONG ( metaLength ),
|
|
||||||
FT_FRAME_ULONG ( metaOrigLength ),
|
|
||||||
FT_FRAME_ULONG ( privOffset ),
|
|
||||||
FT_FRAME_ULONG ( privLength ),
|
|
||||||
FT_FRAME_END
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
FT_ASSERT( stream == face->root.stream );
|
|
||||||
FT_ASSERT( FT_STREAM_POS() == 0 );
|
|
||||||
|
|
||||||
if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) )
|
|
||||||
return error;
|
|
||||||
|
|
||||||
/* Make sure we don't recurse back here or hit TTC code. */
|
|
||||||
if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf )
|
|
||||||
return FT_THROW( Invalid_Table );
|
|
||||||
|
|
||||||
/* Miscellaneous checks. */
|
|
||||||
if ( woff.length != stream->size ||
|
|
||||||
woff.num_tables == 0 ||
|
|
||||||
44 + woff.num_tables * 20UL >= woff.length ||
|
|
||||||
12 + woff.num_tables * 16UL >= woff.totalSfntSize ||
|
|
||||||
( woff.totalSfntSize & 3 ) != 0 ||
|
|
||||||
( woff.metaOffset == 0 && ( woff.metaLength != 0 ||
|
|
||||||
woff.metaOrigLength != 0 ) ) ||
|
|
||||||
( woff.metaLength != 0 && woff.metaOrigLength == 0 ) ||
|
|
||||||
( woff.privOffset == 0 && woff.privLength != 0 ) )
|
|
||||||
{
|
|
||||||
FT_ERROR(( "woff_font_open: invalid WOFF header\n" ));
|
|
||||||
return FT_THROW( Invalid_Table );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't trust `totalSfntSize' before thorough checks. */
|
|
||||||
if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) ||
|
|
||||||
FT_NEW( sfnt_stream ) )
|
|
||||||
goto Exit;
|
|
||||||
|
|
||||||
sfnt_header = sfnt;
|
|
||||||
|
|
||||||
/* Write sfnt header. */
|
|
||||||
{
|
|
||||||
FT_UInt searchRange, entrySelector, rangeShift, x;
|
|
||||||
|
|
||||||
|
|
||||||
x = woff.num_tables;
|
|
||||||
entrySelector = 0;
|
|
||||||
while ( x )
|
|
||||||
{
|
|
||||||
x >>= 1;
|
|
||||||
entrySelector += 1;
|
|
||||||
}
|
|
||||||
entrySelector--;
|
|
||||||
|
|
||||||
searchRange = ( 1 << entrySelector ) * 16;
|
|
||||||
rangeShift = woff.num_tables * 16 - searchRange;
|
|
||||||
|
|
||||||
WRITE_ULONG ( sfnt_header, woff.flavor );
|
|
||||||
WRITE_USHORT( sfnt_header, woff.num_tables );
|
|
||||||
WRITE_USHORT( sfnt_header, searchRange );
|
|
||||||
WRITE_USHORT( sfnt_header, entrySelector );
|
|
||||||
WRITE_USHORT( sfnt_header, rangeShift );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* While the entries in the sfnt header must be sorted by the */
|
|
||||||
/* tag value, the tables themselves are not. We thus have to */
|
|
||||||
/* sort them by offset and check that they don't overlap. */
|
|
||||||
|
|
||||||
if ( FT_NEW_ARRAY( tables, woff.num_tables ) ||
|
|
||||||
FT_NEW_ARRAY( indices, woff.num_tables ) )
|
|
||||||
goto Exit;
|
|
||||||
|
|
||||||
FT_TRACE2(( "\n"
|
|
||||||
" tag offset compLen origLen checksum\n"
|
|
||||||
" -------------------------------------------\n" ));
|
|
||||||
|
|
||||||
if ( FT_FRAME_ENTER( 20L * woff.num_tables ) )
|
|
||||||
goto Exit;
|
|
||||||
|
|
||||||
for ( nn = 0; nn < woff.num_tables; nn++ )
|
|
||||||
{
|
|
||||||
WOFF_Table table = tables + nn;
|
|
||||||
|
|
||||||
table->Tag = FT_GET_TAG4();
|
|
||||||
table->Offset = FT_GET_ULONG();
|
|
||||||
table->CompLength = FT_GET_ULONG();
|
|
||||||
table->OrigLength = FT_GET_ULONG();
|
|
||||||
table->CheckSum = FT_GET_ULONG();
|
|
||||||
|
|
||||||
FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n",
|
|
||||||
(FT_Char)( table->Tag >> 24 ),
|
|
||||||
(FT_Char)( table->Tag >> 16 ),
|
|
||||||
(FT_Char)( table->Tag >> 8 ),
|
|
||||||
(FT_Char)( table->Tag ),
|
|
||||||
table->Offset,
|
|
||||||
table->CompLength,
|
|
||||||
table->OrigLength,
|
|
||||||
table->CheckSum ));
|
|
||||||
|
|
||||||
if ( table->Tag <= old_tag )
|
|
||||||
{
|
|
||||||
FT_FRAME_EXIT();
|
|
||||||
|
|
||||||
FT_ERROR(( "woff_font_open: table tags are not sorted\n" ));
|
|
||||||
error = FT_THROW( Invalid_Table );
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
old_tag = table->Tag;
|
|
||||||
indices[nn] = table;
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_FRAME_EXIT();
|
|
||||||
|
|
||||||
/* Sort by offset. */
|
|
||||||
|
|
||||||
ft_qsort( indices,
|
|
||||||
woff.num_tables,
|
|
||||||
sizeof ( WOFF_Table ),
|
|
||||||
compare_offsets );
|
|
||||||
|
|
||||||
/* Check offsets and lengths. */
|
|
||||||
|
|
||||||
woff_offset = 44 + woff.num_tables * 20L;
|
|
||||||
sfnt_offset = 12 + woff.num_tables * 16L;
|
|
||||||
|
|
||||||
for ( nn = 0; nn < woff.num_tables; nn++ )
|
|
||||||
{
|
|
||||||
WOFF_Table table = indices[nn];
|
|
||||||
|
|
||||||
|
|
||||||
if ( table->Offset != woff_offset ||
|
|
||||||
table->CompLength > woff.length ||
|
|
||||||
table->Offset > woff.length - table->CompLength ||
|
|
||||||
table->OrigLength > woff.totalSfntSize ||
|
|
||||||
sfnt_offset > woff.totalSfntSize - table->OrigLength ||
|
|
||||||
table->CompLength > table->OrigLength )
|
|
||||||
{
|
|
||||||
FT_ERROR(( "woff_font_open: invalid table offsets\n" ));
|
|
||||||
error = FT_THROW( Invalid_Table );
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
table->OrigOffset = sfnt_offset;
|
|
||||||
|
|
||||||
/* The offsets must be multiples of 4. */
|
|
||||||
woff_offset += ( table->CompLength + 3 ) & ~3U;
|
|
||||||
sfnt_offset += ( table->OrigLength + 3 ) & ~3U;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Final checks!
|
|
||||||
*
|
|
||||||
* We don't decode and check the metadata block.
|
|
||||||
* We don't check table checksums either.
|
|
||||||
* But other than those, I think we implement all
|
|
||||||
* `MUST' checks from the spec.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( woff.metaOffset )
|
|
||||||
{
|
|
||||||
if ( woff.metaOffset != woff_offset ||
|
|
||||||
woff.metaOffset + woff.metaLength > woff.length )
|
|
||||||
{
|
|
||||||
FT_ERROR(( "woff_font_open:"
|
|
||||||
" invalid `metadata' offset or length\n" ));
|
|
||||||
error = FT_THROW( Invalid_Table );
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We have padding only ... */
|
|
||||||
woff_offset += woff.metaLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( woff.privOffset )
|
|
||||||
{
|
|
||||||
/* ... if it isn't the last block. */
|
|
||||||
woff_offset = ( woff_offset + 3 ) & ~3U;
|
|
||||||
|
|
||||||
if ( woff.privOffset != woff_offset ||
|
|
||||||
woff.privOffset + woff.privLength > woff.length )
|
|
||||||
{
|
|
||||||
FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" ));
|
|
||||||
error = FT_THROW( Invalid_Table );
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No padding for the last block. */
|
|
||||||
woff_offset += woff.privLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( sfnt_offset != woff.totalSfntSize ||
|
|
||||||
woff_offset != woff.length )
|
|
||||||
{
|
|
||||||
FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" ));
|
|
||||||
error = FT_THROW( Invalid_Table );
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now use `totalSfntSize'. */
|
|
||||||
if ( FT_REALLOC( sfnt,
|
|
||||||
12 + woff.num_tables * 16UL,
|
|
||||||
woff.totalSfntSize ) )
|
|
||||||
goto Exit;
|
|
||||||
|
|
||||||
sfnt_header = sfnt + 12;
|
|
||||||
|
|
||||||
/* Write the tables. */
|
|
||||||
|
|
||||||
for ( nn = 0; nn < woff.num_tables; nn++ )
|
|
||||||
{
|
|
||||||
WOFF_Table table = tables + nn;
|
|
||||||
|
|
||||||
|
|
||||||
/* Write SFNT table entry. */
|
|
||||||
WRITE_ULONG( sfnt_header, table->Tag );
|
|
||||||
WRITE_ULONG( sfnt_header, table->CheckSum );
|
|
||||||
WRITE_ULONG( sfnt_header, table->OrigOffset );
|
|
||||||
WRITE_ULONG( sfnt_header, table->OrigLength );
|
|
||||||
|
|
||||||
/* Write table data. */
|
|
||||||
if ( FT_STREAM_SEEK( table->Offset ) ||
|
|
||||||
FT_FRAME_ENTER( table->CompLength ) )
|
|
||||||
goto Exit;
|
|
||||||
|
|
||||||
if ( table->CompLength == table->OrigLength )
|
|
||||||
{
|
|
||||||
/* Uncompressed data; just copy. */
|
|
||||||
ft_memcpy( sfnt + table->OrigOffset,
|
|
||||||
stream->cursor,
|
|
||||||
table->OrigLength );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef FT_CONFIG_OPTION_USE_ZLIB
|
|
||||||
|
|
||||||
/* Uncompress with zlib. */
|
|
||||||
FT_ULong output_len = table->OrigLength;
|
|
||||||
|
|
||||||
|
|
||||||
error = FT_Gzip_Uncompress( memory,
|
|
||||||
sfnt + table->OrigOffset, &output_len,
|
|
||||||
stream->cursor, table->CompLength );
|
|
||||||
if ( error )
|
|
||||||
goto Exit;
|
|
||||||
if ( output_len != table->OrigLength )
|
|
||||||
{
|
|
||||||
FT_ERROR(( "woff_font_open: compressed table length mismatch\n" ));
|
|
||||||
error = FT_THROW( Invalid_Table );
|
|
||||||
goto Exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* !FT_CONFIG_OPTION_USE_ZLIB */
|
|
||||||
|
|
||||||
error = FT_THROW( Unimplemented_Feature );
|
|
||||||
goto Exit;
|
|
||||||
|
|
||||||
#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_FRAME_EXIT();
|
|
||||||
|
|
||||||
/* We don't check whether the padding bytes in the WOFF file are */
|
|
||||||
/* actually '\0'. For the output, however, we do set them properly. */
|
|
||||||
sfnt_offset = table->OrigOffset + table->OrigLength;
|
|
||||||
while ( sfnt_offset & 3 )
|
|
||||||
{
|
|
||||||
sfnt[sfnt_offset] = '\0';
|
|
||||||
sfnt_offset++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ok! Finally ready. Swap out stream and return. */
|
|
||||||
FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize );
|
|
||||||
sfnt_stream->memory = stream->memory;
|
|
||||||
sfnt_stream->close = sfnt_stream_close;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
Exit:
|
|
||||||
FT_FREE( tables );
|
|
||||||
FT_FREE( indices );
|
|
||||||
|
|
||||||
if ( error )
|
|
||||||
{
|
|
||||||
FT_FREE( sfnt );
|
|
||||||
FT_Stream_Close( sfnt_stream );
|
|
||||||
FT_FREE( sfnt_stream );
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#undef WRITE_USHORT
|
|
||||||
#undef WRITE_ULONG
|
|
||||||
|
|
||||||
|
|
||||||
/* Fill in face->ttc_header. If the font is not a TTC, it is */
|
/* Fill in face->ttc_header. If the font is not a TTC, it is */
|
||||||
/* synthesized into a TTC with one offset table. */
|
/* synthesized into a TTC with one offset table. */
|
||||||
static FT_Error
|
static FT_Error
|
||||||
|
|
|
@ -0,0 +1,434 @@
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* sfwoff.c
|
||||||
|
*
|
||||||
|
* WOFF format management (base).
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996-2019 by
|
||||||
|
* 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 "sfwoff.h"
|
||||||
|
#include FT_TRUETYPE_TAGS_H
|
||||||
|
#include FT_INTERNAL_DEBUG_H
|
||||||
|
#include FT_INTERNAL_STREAM_H
|
||||||
|
#include FT_GZIP_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 sfwoff
|
||||||
|
|
||||||
|
|
||||||
|
#define WRITE_USHORT( p, v ) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
*(p)++ = (FT_Byte)( (v) >> 8 ); \
|
||||||
|
*(p)++ = (FT_Byte)( (v) >> 0 ); \
|
||||||
|
\
|
||||||
|
} while ( 0 )
|
||||||
|
|
||||||
|
#define WRITE_ULONG( p, v ) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
*(p)++ = (FT_Byte)( (v) >> 24 ); \
|
||||||
|
*(p)++ = (FT_Byte)( (v) >> 16 ); \
|
||||||
|
*(p)++ = (FT_Byte)( (v) >> 8 ); \
|
||||||
|
*(p)++ = (FT_Byte)( (v) >> 0 ); \
|
||||||
|
\
|
||||||
|
} while ( 0 )
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
sfnt_stream_close( FT_Stream stream )
|
||||||
|
{
|
||||||
|
FT_Memory memory = stream->memory;
|
||||||
|
|
||||||
|
|
||||||
|
FT_FREE( stream->base );
|
||||||
|
|
||||||
|
stream->size = 0;
|
||||||
|
stream->base = NULL;
|
||||||
|
stream->close = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FT_CALLBACK_DEF( int )
|
||||||
|
compare_offsets( const void* a,
|
||||||
|
const void* b )
|
||||||
|
{
|
||||||
|
WOFF_Table table1 = *(WOFF_Table*)a;
|
||||||
|
WOFF_Table table2 = *(WOFF_Table*)b;
|
||||||
|
|
||||||
|
FT_ULong offset1 = table1->Offset;
|
||||||
|
FT_ULong offset2 = table2->Offset;
|
||||||
|
|
||||||
|
|
||||||
|
if ( offset1 > offset2 )
|
||||||
|
return 1;
|
||||||
|
else if ( offset1 < offset2 )
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Replace `face->root.stream' with a stream containing the extracted */
|
||||||
|
/* SFNT of a WOFF font. */
|
||||||
|
|
||||||
|
FT_LOCAL_DEF( FT_Error )
|
||||||
|
woff_open_font( FT_Stream stream,
|
||||||
|
TT_Face face )
|
||||||
|
{
|
||||||
|
FT_Memory memory = stream->memory;
|
||||||
|
FT_Error error = FT_Err_Ok;
|
||||||
|
|
||||||
|
WOFF_HeaderRec woff;
|
||||||
|
WOFF_Table tables = NULL;
|
||||||
|
WOFF_Table* indices = NULL;
|
||||||
|
|
||||||
|
FT_ULong woff_offset;
|
||||||
|
|
||||||
|
FT_Byte* sfnt = NULL;
|
||||||
|
FT_Stream sfnt_stream = NULL;
|
||||||
|
|
||||||
|
FT_Byte* sfnt_header;
|
||||||
|
FT_ULong sfnt_offset;
|
||||||
|
|
||||||
|
FT_Int nn;
|
||||||
|
FT_ULong old_tag = 0;
|
||||||
|
|
||||||
|
static const FT_Frame_Field woff_header_fields[] =
|
||||||
|
{
|
||||||
|
#undef FT_STRUCTURE
|
||||||
|
#define FT_STRUCTURE WOFF_HeaderRec
|
||||||
|
|
||||||
|
FT_FRAME_START( 44 ),
|
||||||
|
FT_FRAME_ULONG ( signature ),
|
||||||
|
FT_FRAME_ULONG ( flavor ),
|
||||||
|
FT_FRAME_ULONG ( length ),
|
||||||
|
FT_FRAME_USHORT( num_tables ),
|
||||||
|
FT_FRAME_USHORT( reserved ),
|
||||||
|
FT_FRAME_ULONG ( totalSfntSize ),
|
||||||
|
FT_FRAME_USHORT( majorVersion ),
|
||||||
|
FT_FRAME_USHORT( minorVersion ),
|
||||||
|
FT_FRAME_ULONG ( metaOffset ),
|
||||||
|
FT_FRAME_ULONG ( metaLength ),
|
||||||
|
FT_FRAME_ULONG ( metaOrigLength ),
|
||||||
|
FT_FRAME_ULONG ( privOffset ),
|
||||||
|
FT_FRAME_ULONG ( privLength ),
|
||||||
|
FT_FRAME_END
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FT_ASSERT( stream == face->root.stream );
|
||||||
|
FT_ASSERT( FT_STREAM_POS() == 0 );
|
||||||
|
|
||||||
|
if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) )
|
||||||
|
return error;
|
||||||
|
|
||||||
|
/* Make sure we don't recurse back here or hit TTC code. */
|
||||||
|
if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf )
|
||||||
|
return FT_THROW( Invalid_Table );
|
||||||
|
|
||||||
|
/* Miscellaneous checks. */
|
||||||
|
if ( woff.length != stream->size ||
|
||||||
|
woff.num_tables == 0 ||
|
||||||
|
44 + woff.num_tables * 20UL >= woff.length ||
|
||||||
|
12 + woff.num_tables * 16UL >= woff.totalSfntSize ||
|
||||||
|
( woff.totalSfntSize & 3 ) != 0 ||
|
||||||
|
( woff.metaOffset == 0 && ( woff.metaLength != 0 ||
|
||||||
|
woff.metaOrigLength != 0 ) ) ||
|
||||||
|
( woff.metaLength != 0 && woff.metaOrigLength == 0 ) ||
|
||||||
|
( woff.privOffset == 0 && woff.privLength != 0 ) )
|
||||||
|
{
|
||||||
|
FT_ERROR(( "woff_font_open: invalid WOFF header\n" ));
|
||||||
|
return FT_THROW( Invalid_Table );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't trust `totalSfntSize' before thorough checks. */
|
||||||
|
if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) ||
|
||||||
|
FT_NEW( sfnt_stream ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
sfnt_header = sfnt;
|
||||||
|
|
||||||
|
/* Write sfnt header. */
|
||||||
|
{
|
||||||
|
FT_UInt searchRange, entrySelector, rangeShift, x;
|
||||||
|
|
||||||
|
|
||||||
|
x = woff.num_tables;
|
||||||
|
entrySelector = 0;
|
||||||
|
while ( x )
|
||||||
|
{
|
||||||
|
x >>= 1;
|
||||||
|
entrySelector += 1;
|
||||||
|
}
|
||||||
|
entrySelector--;
|
||||||
|
|
||||||
|
searchRange = ( 1 << entrySelector ) * 16;
|
||||||
|
rangeShift = woff.num_tables * 16 - searchRange;
|
||||||
|
|
||||||
|
WRITE_ULONG ( sfnt_header, woff.flavor );
|
||||||
|
WRITE_USHORT( sfnt_header, woff.num_tables );
|
||||||
|
WRITE_USHORT( sfnt_header, searchRange );
|
||||||
|
WRITE_USHORT( sfnt_header, entrySelector );
|
||||||
|
WRITE_USHORT( sfnt_header, rangeShift );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While the entries in the sfnt header must be sorted by the */
|
||||||
|
/* tag value, the tables themselves are not. We thus have to */
|
||||||
|
/* sort them by offset and check that they don't overlap. */
|
||||||
|
|
||||||
|
if ( FT_NEW_ARRAY( tables, woff.num_tables ) ||
|
||||||
|
FT_NEW_ARRAY( indices, woff.num_tables ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
FT_TRACE2(( "\n"
|
||||||
|
" tag offset compLen origLen checksum\n"
|
||||||
|
" -------------------------------------------\n" ));
|
||||||
|
|
||||||
|
if ( FT_FRAME_ENTER( 20L * woff.num_tables ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
for ( nn = 0; nn < woff.num_tables; nn++ )
|
||||||
|
{
|
||||||
|
WOFF_Table table = tables + nn;
|
||||||
|
|
||||||
|
table->Tag = FT_GET_TAG4();
|
||||||
|
table->Offset = FT_GET_ULONG();
|
||||||
|
table->CompLength = FT_GET_ULONG();
|
||||||
|
table->OrigLength = FT_GET_ULONG();
|
||||||
|
table->CheckSum = FT_GET_ULONG();
|
||||||
|
|
||||||
|
FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n",
|
||||||
|
(FT_Char)( table->Tag >> 24 ),
|
||||||
|
(FT_Char)( table->Tag >> 16 ),
|
||||||
|
(FT_Char)( table->Tag >> 8 ),
|
||||||
|
(FT_Char)( table->Tag ),
|
||||||
|
table->Offset,
|
||||||
|
table->CompLength,
|
||||||
|
table->OrigLength,
|
||||||
|
table->CheckSum ));
|
||||||
|
|
||||||
|
if ( table->Tag <= old_tag )
|
||||||
|
{
|
||||||
|
FT_FRAME_EXIT();
|
||||||
|
|
||||||
|
FT_ERROR(( "woff_font_open: table tags are not sorted\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_tag = table->Tag;
|
||||||
|
indices[nn] = table;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_FRAME_EXIT();
|
||||||
|
|
||||||
|
/* Sort by offset. */
|
||||||
|
|
||||||
|
ft_qsort( indices,
|
||||||
|
woff.num_tables,
|
||||||
|
sizeof ( WOFF_Table ),
|
||||||
|
compare_offsets );
|
||||||
|
|
||||||
|
/* Check offsets and lengths. */
|
||||||
|
|
||||||
|
woff_offset = 44 + woff.num_tables * 20L;
|
||||||
|
sfnt_offset = 12 + woff.num_tables * 16L;
|
||||||
|
|
||||||
|
for ( nn = 0; nn < woff.num_tables; nn++ )
|
||||||
|
{
|
||||||
|
WOFF_Table table = indices[nn];
|
||||||
|
|
||||||
|
|
||||||
|
if ( table->Offset != woff_offset ||
|
||||||
|
table->CompLength > woff.length ||
|
||||||
|
table->Offset > woff.length - table->CompLength ||
|
||||||
|
table->OrigLength > woff.totalSfntSize ||
|
||||||
|
sfnt_offset > woff.totalSfntSize - table->OrigLength ||
|
||||||
|
table->CompLength > table->OrigLength )
|
||||||
|
{
|
||||||
|
FT_ERROR(( "woff_font_open: invalid table offsets\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->OrigOffset = sfnt_offset;
|
||||||
|
|
||||||
|
/* The offsets must be multiples of 4. */
|
||||||
|
woff_offset += ( table->CompLength + 3 ) & ~3U;
|
||||||
|
sfnt_offset += ( table->OrigLength + 3 ) & ~3U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Final checks!
|
||||||
|
*
|
||||||
|
* We don't decode and check the metadata block.
|
||||||
|
* We don't check table checksums either.
|
||||||
|
* But other than those, I think we implement all
|
||||||
|
* `MUST' checks from the spec.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( woff.metaOffset )
|
||||||
|
{
|
||||||
|
if ( woff.metaOffset != woff_offset ||
|
||||||
|
woff.metaOffset + woff.metaLength > woff.length )
|
||||||
|
{
|
||||||
|
FT_ERROR(( "woff_font_open:"
|
||||||
|
" invalid `metadata' offset or length\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have padding only ... */
|
||||||
|
woff_offset += woff.metaLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( woff.privOffset )
|
||||||
|
{
|
||||||
|
/* ... if it isn't the last block. */
|
||||||
|
woff_offset = ( woff_offset + 3 ) & ~3U;
|
||||||
|
|
||||||
|
if ( woff.privOffset != woff_offset ||
|
||||||
|
woff.privOffset + woff.privLength > woff.length )
|
||||||
|
{
|
||||||
|
FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No padding for the last block. */
|
||||||
|
woff_offset += woff.privLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( sfnt_offset != woff.totalSfntSize ||
|
||||||
|
woff_offset != woff.length )
|
||||||
|
{
|
||||||
|
FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now use `totalSfntSize'. */
|
||||||
|
if ( FT_REALLOC( sfnt,
|
||||||
|
12 + woff.num_tables * 16UL,
|
||||||
|
woff.totalSfntSize ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
sfnt_header = sfnt + 12;
|
||||||
|
|
||||||
|
/* Write the tables. */
|
||||||
|
|
||||||
|
for ( nn = 0; nn < woff.num_tables; nn++ )
|
||||||
|
{
|
||||||
|
WOFF_Table table = tables + nn;
|
||||||
|
|
||||||
|
|
||||||
|
/* Write SFNT table entry. */
|
||||||
|
WRITE_ULONG( sfnt_header, table->Tag );
|
||||||
|
WRITE_ULONG( sfnt_header, table->CheckSum );
|
||||||
|
WRITE_ULONG( sfnt_header, table->OrigOffset );
|
||||||
|
WRITE_ULONG( sfnt_header, table->OrigLength );
|
||||||
|
|
||||||
|
/* Write table data. */
|
||||||
|
if ( FT_STREAM_SEEK( table->Offset ) ||
|
||||||
|
FT_FRAME_ENTER( table->CompLength ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
if ( table->CompLength == table->OrigLength )
|
||||||
|
{
|
||||||
|
/* Uncompressed data; just copy. */
|
||||||
|
ft_memcpy( sfnt + table->OrigOffset,
|
||||||
|
stream->cursor,
|
||||||
|
table->OrigLength );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef FT_CONFIG_OPTION_USE_ZLIB
|
||||||
|
|
||||||
|
/* Uncompress with zlib. */
|
||||||
|
FT_ULong output_len = table->OrigLength;
|
||||||
|
|
||||||
|
|
||||||
|
error = FT_Gzip_Uncompress( memory,
|
||||||
|
sfnt + table->OrigOffset, &output_len,
|
||||||
|
stream->cursor, table->CompLength );
|
||||||
|
if ( error )
|
||||||
|
goto Exit;
|
||||||
|
if ( output_len != table->OrigLength )
|
||||||
|
{
|
||||||
|
FT_ERROR(( "woff_font_open: compressed table length mismatch\n" ));
|
||||||
|
error = FT_THROW( Invalid_Table );
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !FT_CONFIG_OPTION_USE_ZLIB */
|
||||||
|
|
||||||
|
error = FT_THROW( Unimplemented_Feature );
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_FRAME_EXIT();
|
||||||
|
|
||||||
|
/* We don't check whether the padding bytes in the WOFF file are */
|
||||||
|
/* actually '\0'. For the output, however, we do set them properly. */
|
||||||
|
sfnt_offset = table->OrigOffset + table->OrigLength;
|
||||||
|
while ( sfnt_offset & 3 )
|
||||||
|
{
|
||||||
|
sfnt[sfnt_offset] = '\0';
|
||||||
|
sfnt_offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ok! Finally ready. Swap out stream and return. */
|
||||||
|
FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize );
|
||||||
|
sfnt_stream->memory = stream->memory;
|
||||||
|
sfnt_stream->close = sfnt_stream_close;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
Exit:
|
||||||
|
FT_FREE( tables );
|
||||||
|
FT_FREE( indices );
|
||||||
|
|
||||||
|
if ( error )
|
||||||
|
{
|
||||||
|
FT_FREE( sfnt );
|
||||||
|
FT_Stream_Close( sfnt_stream );
|
||||||
|
FT_FREE( sfnt_stream );
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef WRITE_USHORT
|
||||||
|
#undef WRITE_ULONG
|
||||||
|
|
||||||
|
|
||||||
|
/* END */
|
|
@ -0,0 +1,41 @@
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* sfwoff.h
|
||||||
|
*
|
||||||
|
* WOFFF format management (specification).
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996-2019 by
|
||||||
|
* 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 SFWOFF_H_
|
||||||
|
#define SFWOFF_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_INTERNAL_SFNT_H
|
||||||
|
#include FT_INTERNAL_OBJECTS_H
|
||||||
|
|
||||||
|
|
||||||
|
FT_BEGIN_HEADER
|
||||||
|
|
||||||
|
|
||||||
|
FT_LOCAL( FT_Error )
|
||||||
|
woff_open_font( FT_Stream stream,
|
||||||
|
TT_Face face );
|
||||||
|
|
||||||
|
|
||||||
|
FT_END_HEADER
|
||||||
|
|
||||||
|
#endif /* SFWOFF_H_ */
|
||||||
|
|
||||||
|
|
||||||
|
/* END */
|
Loading…
Reference in New Issue