[sfnt] Support `name' table format 1.
* include/freetype/internal/tttypes.h (TT_LangTagRec): New structure. (TT_NameTableRec): Add fields `numLangTagRecords' and `langTags'. * src/sfnt/ttload.c (tt_face_load_name): Add support for language tags. Reduce array size of name strings in case of invalid entries. (tt_face_free_name): Updated. * docs/CHANGES: Updated.
This commit is contained in:
parent
f4e5696643
commit
939df42072
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
2017-01-26 Werner Lemberg <wl@gnu.org>
|
||||||
|
|
||||||
|
[sfnt] Support `name' table format 1.
|
||||||
|
|
||||||
|
* include/freetype/internal/tttypes.h (TT_LangTagRec): New
|
||||||
|
structure.
|
||||||
|
(TT_NameTableRec): Add fields `numLangTagRecords' and `langTags'.
|
||||||
|
|
||||||
|
* src/sfnt/ttload.c (tt_face_load_name): Add support for language
|
||||||
|
tags.
|
||||||
|
Reduce array size of name strings in case of invalid entries.
|
||||||
|
(tt_face_free_name): Updated.
|
||||||
|
|
||||||
|
* docs/CHANGES: Updated.
|
||||||
|
|
||||||
2017-01-25 Werner Lemberg <wl@gnu.org>
|
2017-01-25 Werner Lemberg <wl@gnu.org>
|
||||||
|
|
||||||
[sfnt] s/TT_NameEntry/TT_Name/.
|
[sfnt] s/TT_NameEntry/TT_Name/.
|
||||||
|
|
|
@ -39,6 +39,13 @@ CHANGES BETWEEN 2.7.1 and 2.7.2
|
||||||
|
|
||||||
The old macro names are deprecated (but still available).
|
The old macro names are deprecated (but still available).
|
||||||
|
|
||||||
|
- Support for SFNT `name' tables has been improved.
|
||||||
|
|
||||||
|
. Format 1 `name' tables are now supported.
|
||||||
|
|
||||||
|
. Language ID and name ID values have been updated to OpenType version
|
||||||
|
1.8.1.
|
||||||
|
|
||||||
|
|
||||||
======================================================================
|
======================================================================
|
||||||
|
|
||||||
|
|
|
@ -279,11 +279,41 @@ FT_BEGIN_HEADER
|
||||||
/* this last field is not defined in the spec */
|
/* this last field is not defined in the spec */
|
||||||
/* but used by the FreeType engine */
|
/* but used by the FreeType engine */
|
||||||
|
|
||||||
FT_Byte* string;
|
FT_Byte* string;
|
||||||
|
|
||||||
} TT_NameRec, *TT_Name;
|
} TT_NameRec, *TT_Name;
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* <Struct> */
|
||||||
|
/* TT_LangTagRec */
|
||||||
|
/* */
|
||||||
|
/* <Description> */
|
||||||
|
/* A structure modeling language tag records in SFNT `name' tables, */
|
||||||
|
/* introduced in OpenType version 1.6. */
|
||||||
|
/* */
|
||||||
|
/* <Fields> */
|
||||||
|
/* stringLength :: The length of the string in bytes. */
|
||||||
|
/* */
|
||||||
|
/* stringOffset :: The offset to the string in the `name' table. */
|
||||||
|
/* */
|
||||||
|
/* string :: A pointer to the string's bytes. Note that these */
|
||||||
|
/* are UTF-16BE encoded characters. */
|
||||||
|
/* */
|
||||||
|
typedef struct TT_LangTagRec_
|
||||||
|
{
|
||||||
|
FT_UShort stringLength;
|
||||||
|
FT_ULong stringOffset;
|
||||||
|
|
||||||
|
/* this last field is not defined in the spec */
|
||||||
|
/* but used by the FreeType engine */
|
||||||
|
|
||||||
|
FT_Byte* string;
|
||||||
|
|
||||||
|
} TT_LangTagRec, *TT_LangTag;
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* */
|
/* */
|
||||||
/* <Struct> */
|
/* <Struct> */
|
||||||
|
@ -293,24 +323,30 @@ FT_BEGIN_HEADER
|
||||||
/* A structure modeling the TrueType name table. */
|
/* A structure modeling the TrueType name table. */
|
||||||
/* */
|
/* */
|
||||||
/* <Fields> */
|
/* <Fields> */
|
||||||
/* format :: The format of the name table. */
|
/* format :: The format of the name table. */
|
||||||
/* */
|
/* */
|
||||||
/* numNameRecords :: The number of names in table. */
|
/* numNameRecords :: The number of names in table. */
|
||||||
/* */
|
/* */
|
||||||
/* storageOffset :: The offset of the name table in the `name' */
|
/* storageOffset :: The offset of the name table in the `name' */
|
||||||
/* TrueType table. */
|
/* TrueType table. */
|
||||||
/* */
|
/* */
|
||||||
/* names :: An array of name records. */
|
/* names :: An array of name records. */
|
||||||
/* */
|
/* */
|
||||||
/* stream :: the file's input stream. */
|
/* numLangTagRecords :: The number of language tags in table. */
|
||||||
|
/* */
|
||||||
|
/* langTags :: An array of language tag records. */
|
||||||
|
/* */
|
||||||
|
/* stream :: The file's input stream. */
|
||||||
/* */
|
/* */
|
||||||
typedef struct TT_NameTableRec_
|
typedef struct TT_NameTableRec_
|
||||||
{
|
{
|
||||||
FT_UShort format;
|
FT_UShort format;
|
||||||
FT_UInt numNameRecords;
|
FT_UInt numNameRecords;
|
||||||
FT_UInt storageOffset;
|
FT_UInt storageOffset;
|
||||||
TT_NameRec* names;
|
TT_NameRec* names;
|
||||||
FT_Stream stream;
|
FT_UInt numLangTagRecords;
|
||||||
|
TT_LangTagRec* langTags;
|
||||||
|
FT_Stream stream;
|
||||||
|
|
||||||
} TT_NameTableRec, *TT_NameTable;
|
} TT_NameTableRec, *TT_NameTable;
|
||||||
|
|
||||||
|
|
|
@ -808,7 +808,6 @@
|
||||||
FT_Memory memory = stream->memory;
|
FT_Memory memory = stream->memory;
|
||||||
FT_ULong table_pos, table_len;
|
FT_ULong table_pos, table_len;
|
||||||
FT_ULong storage_start, storage_limit;
|
FT_ULong storage_start, storage_limit;
|
||||||
FT_UInt count;
|
|
||||||
TT_NameTable table;
|
TT_NameTable table;
|
||||||
|
|
||||||
static const FT_Frame_Field name_table_fields[] =
|
static const FT_Frame_Field name_table_fields[] =
|
||||||
|
@ -838,6 +837,17 @@
|
||||||
FT_FRAME_END
|
FT_FRAME_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const FT_Frame_Field langTag_record_fields[] =
|
||||||
|
{
|
||||||
|
#undef FT_STRUCTURE
|
||||||
|
#define FT_STRUCTURE TT_LangTagRec
|
||||||
|
|
||||||
|
/* no FT_FRAME_START */
|
||||||
|
FT_FRAME_USHORT( stringLength ),
|
||||||
|
FT_FRAME_USHORT( stringOffset ),
|
||||||
|
FT_FRAME_END
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
table = &face->name_table;
|
table = &face->name_table;
|
||||||
table->stream = stream;
|
table->stream = stream;
|
||||||
|
@ -848,18 +858,17 @@
|
||||||
|
|
||||||
table_pos = FT_STREAM_POS();
|
table_pos = FT_STREAM_POS();
|
||||||
|
|
||||||
|
|
||||||
if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) )
|
if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) )
|
||||||
goto Exit;
|
goto Exit;
|
||||||
|
|
||||||
/* Some popular Asian fonts have an invalid `storageOffset' value */
|
/* Some popular Asian fonts have an invalid `storageOffset' value (it */
|
||||||
/* (it should be at least "6 + 12*num_names"). However, the string */
|
/* should be at least `6 + 12*numNameRecords'). However, the string */
|
||||||
/* offsets, computed as "storageOffset + entry->stringOffset", are */
|
/* offsets, computed as `storageOffset + entry->stringOffset', are */
|
||||||
/* valid pointers within the name table... */
|
/* valid pointers within the name table... */
|
||||||
/* */
|
/* */
|
||||||
/* We thus can't check `storageOffset' right now. */
|
/* We thus can't check `storageOffset' right now. */
|
||||||
/* */
|
/* */
|
||||||
storage_start = table_pos + 6 + 12*table->numNameRecords;
|
storage_start = table_pos + 6 + 12 * table->numNameRecords;
|
||||||
storage_limit = table_pos + table_len;
|
storage_limit = table_pos + table_len;
|
||||||
|
|
||||||
if ( storage_start > storage_limit )
|
if ( storage_start > storage_limit )
|
||||||
|
@ -869,18 +878,56 @@
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate the array of name records. */
|
/* `name' format 1 contains additional language tag records, */
|
||||||
count = table->numNameRecords;
|
/* which we load first */
|
||||||
table->numNameRecords = 0;
|
if ( table->format == 1 )
|
||||||
|
{
|
||||||
|
if ( FT_STREAM_SEEK( storage_start ) ||
|
||||||
|
FT_READ_USHORT( table->numLangTagRecords ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
if ( FT_NEW_ARRAY( table->names, count ) ||
|
storage_start += 2 + 4 * table->numLangTagRecords;
|
||||||
FT_FRAME_ENTER( count * 12 ) )
|
|
||||||
|
/* allocate language tag records array */
|
||||||
|
if ( FT_NEW_ARRAY( table->langTags, table->numLangTagRecords ) ||
|
||||||
|
FT_FRAME_ENTER( table->numLangTagRecords * 4 ) )
|
||||||
|
goto Exit;
|
||||||
|
|
||||||
|
/* load language tags */
|
||||||
|
{
|
||||||
|
TT_LangTag entry = table->langTags;
|
||||||
|
TT_LangTag limit = entry + table->numLangTagRecords;
|
||||||
|
|
||||||
|
|
||||||
|
for ( ; entry < limit; entry++ )
|
||||||
|
{
|
||||||
|
(void)FT_STREAM_READ_FIELDS( langTag_record_fields, entry );
|
||||||
|
|
||||||
|
/* check that the langTag string is within the table */
|
||||||
|
entry->stringOffset += table_pos + table->storageOffset;
|
||||||
|
if ( entry->stringOffset < storage_start ||
|
||||||
|
entry->stringOffset + entry->stringLength > storage_limit )
|
||||||
|
{
|
||||||
|
/* invalid entry; ignore it */
|
||||||
|
entry->stringLength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_FRAME_EXIT();
|
||||||
|
|
||||||
|
(void)FT_STREAM_SEEK( table_pos + 6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate name records array */
|
||||||
|
if ( FT_NEW_ARRAY( table->names, table->numNameRecords ) ||
|
||||||
|
FT_FRAME_ENTER( table->numNameRecords * 12 ) )
|
||||||
goto Exit;
|
goto Exit;
|
||||||
|
|
||||||
/* Load the name records and determine how much storage is needed */
|
/* load name records */
|
||||||
/* to hold the strings themselves. */
|
|
||||||
{
|
{
|
||||||
TT_Name entry = table->names;
|
TT_Name entry = table->names;
|
||||||
|
FT_UInt count = table->numNameRecords;
|
||||||
|
|
||||||
|
|
||||||
for ( ; count > 0; count-- )
|
for ( ; count > 0; count-- )
|
||||||
|
@ -897,22 +944,37 @@
|
||||||
if ( entry->stringOffset < storage_start ||
|
if ( entry->stringOffset < storage_start ||
|
||||||
entry->stringOffset + entry->stringLength > storage_limit )
|
entry->stringOffset + entry->stringLength > storage_limit )
|
||||||
{
|
{
|
||||||
/* invalid entry - ignore it */
|
/* invalid entry; ignore it */
|
||||||
entry->stringOffset = 0;
|
|
||||||
entry->stringLength = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* assure that we have a valid language tag ID, and */
|
||||||
|
/* that the corresponding langTag entry is valid, too */
|
||||||
|
if ( table->format == 1 && entry->languageID >= 0x8000U )
|
||||||
|
{
|
||||||
|
if ( entry->languageID - 0x8000U >= table->numLangTagRecords ||
|
||||||
|
!table->langTags[entry->languageID - 0x8000U].stringLength )
|
||||||
|
{
|
||||||
|
/* invalid entry; ignore it */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
entry++;
|
entry++;
|
||||||
}
|
}
|
||||||
|
|
||||||
table->numNameRecords = (FT_UInt)( entry - table->names );
|
/* reduce array size to the actually used elements */
|
||||||
|
count = (FT_UInt)( entry - table->names );
|
||||||
|
(void)FT_RENEW_ARRAY( table->names,
|
||||||
|
table->numNameRecords,
|
||||||
|
count );
|
||||||
|
table->numNameRecords = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_FRAME_EXIT();
|
FT_FRAME_EXIT();
|
||||||
|
|
||||||
/* everything went well, update face->num_names */
|
/* everything went well, update face->num_names */
|
||||||
face->num_names = (FT_UShort) table->numNameRecords;
|
face->num_names = (FT_UShort)table->numNameRecords;
|
||||||
|
|
||||||
Exit:
|
Exit:
|
||||||
return error;
|
return error;
|
||||||
|
@ -935,25 +997,36 @@
|
||||||
{
|
{
|
||||||
FT_Memory memory = face->root.driver->root.memory;
|
FT_Memory memory = face->root.driver->root.memory;
|
||||||
TT_NameTable table = &face->name_table;
|
TT_NameTable table = &face->name_table;
|
||||||
TT_Name entry = table->names;
|
|
||||||
FT_UInt count = table->numNameRecords;
|
|
||||||
|
|
||||||
|
|
||||||
if ( table->names )
|
if ( table->names )
|
||||||
{
|
{
|
||||||
for ( ; count > 0; count--, entry++ )
|
TT_Name entry = table->names;
|
||||||
{
|
TT_Name limit = entry + table->numNameRecords;
|
||||||
FT_FREE( entry->string );
|
|
||||||
entry->stringLength = 0;
|
|
||||||
}
|
for ( ; entry < limit; entry++ )
|
||||||
|
FT_FREE( entry->string );
|
||||||
|
|
||||||
/* free strings table */
|
|
||||||
FT_FREE( table->names );
|
FT_FREE( table->names );
|
||||||
}
|
}
|
||||||
|
|
||||||
table->numNameRecords = 0;
|
if ( table->langTags )
|
||||||
table->format = 0;
|
{
|
||||||
table->storageOffset = 0;
|
TT_LangTag entry = table->langTags;
|
||||||
|
TT_LangTag limit = entry + table->numLangTagRecords;
|
||||||
|
|
||||||
|
|
||||||
|
for ( ; entry < limit; entry++ )
|
||||||
|
FT_FREE( entry->string );
|
||||||
|
|
||||||
|
FT_FREE( table->langTags );
|
||||||
|
}
|
||||||
|
|
||||||
|
table->numNameRecords = 0;
|
||||||
|
table->numLangTagRecords = 0;
|
||||||
|
table->format = 0;
|
||||||
|
table->storageOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue