[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:
Werner Lemberg 2017-01-26 21:41:38 +01:00
parent f4e5696643
commit 939df42072
4 changed files with 176 additions and 45 deletions

View File

@ -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>
[sfnt] s/TT_NameEntry/TT_Name/.

View File

@ -39,6 +39,13 @@ CHANGES BETWEEN 2.7.1 and 2.7.2
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.
======================================================================

View File

@ -279,11 +279,41 @@ FT_BEGIN_HEADER
/* this last field is not defined in the spec */
/* but used by the FreeType engine */
FT_Byte* string;
FT_Byte* string;
} 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> */
@ -293,24 +323,30 @@ FT_BEGIN_HEADER
/* A structure modeling the TrueType name table. */
/* */
/* <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' */
/* TrueType table. */
/* storageOffset :: The offset of the name table in the `name' */
/* 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_
{
FT_UShort format;
FT_UInt numNameRecords;
FT_UInt storageOffset;
TT_NameRec* names;
FT_Stream stream;
FT_UShort format;
FT_UInt numNameRecords;
FT_UInt storageOffset;
TT_NameRec* names;
FT_UInt numLangTagRecords;
TT_LangTagRec* langTags;
FT_Stream stream;
} TT_NameTableRec, *TT_NameTable;

View File

@ -808,7 +808,6 @@
FT_Memory memory = stream->memory;
FT_ULong table_pos, table_len;
FT_ULong storage_start, storage_limit;
FT_UInt count;
TT_NameTable table;
static const FT_Frame_Field name_table_fields[] =
@ -838,6 +837,17 @@
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->stream = stream;
@ -848,18 +858,17 @@
table_pos = FT_STREAM_POS();
if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) )
goto Exit;
/* Some popular Asian fonts have an invalid `storageOffset' value */
/* (it should be at least "6 + 12*num_names"). However, the string */
/* offsets, computed as "storageOffset + entry->stringOffset", are */
/* valid pointers within the name table... */
/* */
/* We thus can't check `storageOffset' right now. */
/* */
storage_start = table_pos + 6 + 12*table->numNameRecords;
/* Some popular Asian fonts have an invalid `storageOffset' value (it */
/* should be at least `6 + 12*numNameRecords'). However, the string */
/* offsets, computed as `storageOffset + entry->stringOffset', are */
/* valid pointers within the name table... */
/* */
/* We thus can't check `storageOffset' right now. */
/* */
storage_start = table_pos + 6 + 12 * table->numNameRecords;
storage_limit = table_pos + table_len;
if ( storage_start > storage_limit )
@ -869,18 +878,56 @@
goto Exit;
}
/* Allocate the array of name records. */
count = table->numNameRecords;
table->numNameRecords = 0;
/* `name' format 1 contains additional language tag records, */
/* which we load first */
if ( table->format == 1 )
{
if ( FT_STREAM_SEEK( storage_start ) ||
FT_READ_USHORT( table->numLangTagRecords ) )
goto Exit;
if ( FT_NEW_ARRAY( table->names, count ) ||
FT_FRAME_ENTER( count * 12 ) )
storage_start += 2 + 4 * table->numLangTagRecords;
/* 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;
/* Load the name records and determine how much storage is needed */
/* to hold the strings themselves. */
/* load name records */
{
TT_Name entry = table->names;
FT_UInt count = table->numNameRecords;
for ( ; count > 0; count-- )
@ -897,22 +944,37 @@
if ( entry->stringOffset < storage_start ||
entry->stringOffset + entry->stringLength > storage_limit )
{
/* invalid entry - ignore it */
entry->stringOffset = 0;
entry->stringLength = 0;
/* invalid entry; ignore it */
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++;
}
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();
/* everything went well, update face->num_names */
face->num_names = (FT_UShort) table->numNameRecords;
face->num_names = (FT_UShort)table->numNameRecords;
Exit:
return error;
@ -935,25 +997,36 @@
{
FT_Memory memory = face->root.driver->root.memory;
TT_NameTable table = &face->name_table;
TT_Name entry = table->names;
FT_UInt count = table->numNameRecords;
if ( table->names )
{
for ( ; count > 0; count--, entry++ )
{
FT_FREE( entry->string );
entry->stringLength = 0;
}
TT_Name entry = table->names;
TT_Name limit = entry + table->numNameRecords;
for ( ; entry < limit; entry++ )
FT_FREE( entry->string );
/* free strings table */
FT_FREE( table->names );
}
table->numNameRecords = 0;
table->format = 0;
table->storageOffset = 0;
if ( table->langTags )
{
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;
}