X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fotfopen.c;h=2cdb3f5b09b3d0d7028bb20c282fba62fa31b6bb;hb=322ee2c98babc81ec26df629b5ea08288e3187da;hp=cef7e16739a44aa1c6959fa80dc79376fdb58194;hpb=a837457673fd479df765fdfa1cc4d8d585defdbc;p=m17n%2Flibotf.git diff --git a/src/otfopen.c b/src/otfopen.c index cef7e16..2cdb3f5 100644 --- a/src/otfopen.c +++ b/src/otfopen.c @@ -1,11 +1,73 @@ +/* otfopen.c -- OpenType font reader. + +Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 + National Institute of Advanced Industrial Science and Technology (AIST) + Registration Number H15PRO167 + +This file is part of libotf. + +Libotf is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +Libotf is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library, in a file named COPYING; if not, +write to the Free Software Foundation, Inc., 59 Temple Place, Suite +330, Boston, MA 02111-1307, USA. */ + #include #include #include +#include #include "otf.h" #include "otferror.h" -/* OTF_Stream +#include FT_TRUETYPE_TABLES_H + +/*** + Table of contents (almost parallel to otf.h): + + (0) Stream handler + + (1) Readers for OTF Layout tables and OTF itself + (1-1) Basic types and functions + (1-2) "head" table + (1-3) "name" table + (1-4) "cmap" table + (1-5) Structures common to GDEF, GSUB, and GPOS + (1-6) "GDEF" table + (1-7) Structures for ScriptList, FeatureList, and LookupList + (1-8) Structures common to GSUB and GPOS + (1-9) "GSUB" table + (1-10) "GPOS" table + (1-11) Structure for OTF + + (2) API for reading OTF + (2-1) OTF_open() + (2-2) OTF_close() + (2-3) OTF_get_table() + (2-4) OTF_check_table() + + (5) API miscellaneous +*/ + +int debug_flag = -1; + +static void +set_debug_flag () +{ + debug_flag = getenv ("LIBOTF_DEBUG") != NULL; +} + + +/* (0) Stream handler Example of typical usage of OTF_Stream. @@ -29,8 +91,7 @@ typedef struct { - FILE *fp; - char *name; + const char *name; long pos; long bufsize; long allocated; @@ -39,27 +100,26 @@ typedef struct typedef long OTF_StreamState; -OTF_Stream * -make_stream () +static OTF_Stream * +make_stream (const char *name) { OTF_Stream *stream; char *errfmt = "stream creation%s"; void *errret = NULL; - stream = malloc (sizeof (OTF_Stream)); + stream = calloc (1, sizeof (OTF_Stream)); if (! stream) OTF_ERROR (OTF_ERROR_MEMORY, ""); + stream->name = name; return stream; } -int -setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes, - char *name) +static int +setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes) { char *errfmt = "stream setup for %s"; int errret = -1; - stream->name = name; stream->pos = 0; if (stream->allocated < nbytes) { @@ -80,11 +140,41 @@ setup_stream (OTF_Stream *stream, FILE *fp, long offset, int nbytes, return 0; } +static OTF_Stream * +make_stream_from_ft_face (FT_Face face, const char *name) +{ + char *errfmt = "FT_Face stream creation for %s"; + void *errret = NULL; + FT_ULong nbytes = 0; + unsigned char *buf; + OTF_Stream *stream; + FT_ULong tag = FT_MAKE_TAG (name[0], name[1], name[2], name[3]); -void + if (FT_Load_Sfnt_Table (face, tag, 0, NULL, &nbytes)) + return NULL; + buf = malloc (nbytes); + if (! buf) + OTF_ERROR (OTF_ERROR_MEMORY, name); + if (FT_Load_Sfnt_Table (face, tag, 0, buf, &nbytes)) + { + free (buf); + OTF_ERROR (OTF_ERROR_FT_FACE, name); + } + stream = make_stream (name); + if (! stream) + return NULL; + stream->pos = 0; + stream->buf = buf; + stream->allocated = nbytes; + stream->bufsize = nbytes; + return stream; +} + +static void free_stream (OTF_Stream *stream) { - free (stream->buf); + if (stream->buf) + free (stream->buf); free (stream); } @@ -119,6 +209,15 @@ free_stream (OTF_Stream *stream) (stream)->pos += 2; \ } while (0) +#define READ_UINT24(stream, var) \ + do { \ + STREAM_CHECK_SIZE ((stream), 3); \ + (var) = (((stream)->buf[(stream)->pos ] << 16) \ + | ((stream)->buf[(stream)->pos + 1] << 8) \ + | (stream)->buf[(stream)->pos + 2]); \ + (stream)->pos += 3; \ + } while (0) + #define READ_ULONG(stream, var) \ do { \ STREAM_CHECK_SIZE ((stream), 4); \ @@ -162,6 +261,9 @@ free_stream (OTF_Stream *stream) #define READ_GLYPHID READ_USHORT +/*** (1) Structures for OTF Layout tables and OTF itself */ + +/*** (1-1) Basic types and functions */ enum OTF_TableType { @@ -185,15 +287,36 @@ struct OTF_MemoryRecord typedef struct OTF_MemoryRecord OTF_MemoryRecord; -typedef struct +enum OTF_ReaderFlag + { + OTF_READ_FULL, + OTF_READ_SCRIPTS, + OTF_READ_FEATURES, + OTF_READ_MAX + }; + +struct _OTF_TableInfo; +typedef struct _OTF_TableInfo OTF_TableInfo; + +struct _OTF_TableInfo { /* Points to one of OTF->head, OTF->name, etc. */ void **address; /* Function to read one of OTF tables. */ - void *(*reader) (OTF *otf, OTF_Stream *stream); + void *(*reader) (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag); /* Stream given to . */ OTF_Stream *stream; -} OTF_TableInfo; +}; + +struct _OTF_ApplicationData +{ + char *id; + void *data; + void (*freer) (void *data); + struct _OTF_ApplicationData *next; +}; + +typedef struct _OTF_ApplicationData OTF_ApplicationData; struct OTF_InternalData { @@ -205,6 +328,9 @@ struct OTF_InternalData /* Records of allocated memories. */ OTF_MemoryRecord *memory_record; + + /* Root of application data chain. */ + OTF_ApplicationData *app_data; }; @@ -259,138 +385,13 @@ allocate_memory_record (OTF *otf) } \ } while (0) - - - -static void *read_head_table (OTF *otf, OTF_Stream *stream); -static void *read_name_table (OTF *otf, OTF_Stream *stream); -static void *read_cmap_table (OTF *otf, OTF_Stream *stream); -static void *read_gdef_table (OTF *otf, OTF_Stream *stream); -static void *read_gsub_table (OTF *otf, OTF_Stream *stream); -static void *read_gpos_table (OTF *otf, OTF_Stream *stream); - -int -read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table) -{ - int errret = -1; - - READ_FIXED (stream, table->sfnt_version); - READ_USHORT (stream, table->numTables); - READ_USHORT (stream, table->searchRange); - READ_USHORT (stream, table->enterSelector); - READ_USHORT (stream, table->rangeShift); - return 0; -} - -static OTF_Tag -read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table) -{ - int errret = 0; - OTF_Tag tag; - - READ_TAG (stream, tag); - table->tag = tag; - table->name[0] = tag >> 24; - table->name[1] = (tag >> 16) & 0xFF; - table->name[0] = (tag >> 8) & 0xFF; - table->name[0] = tag >> 8; - table->name[0] = '\0'; - READ_ULONG (stream, table->checkSum); - READ_ULONG (stream, table->offset); - READ_ULONG (stream, table->length); - return tag; -} - -static int -read_header_part (OTF *otf, FILE *fp) -{ - char *errfmt = "otf header%s"; - int errret = -1; - OTF_Tag head_tag, name_tag, cmap_tag, gdef_tag, gsub_tag, gpos_tag; - OTF_Stream *stream; - int i; - OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; - - internal_data->table_info[OTF_TABLE_TYPE_HEAD].address = (void *) &otf->head; - internal_data->table_info[OTF_TABLE_TYPE_HEAD].reader = read_head_table; - internal_data->table_info[OTF_TABLE_TYPE_NAME].address = (void *) &otf->name; - internal_data->table_info[OTF_TABLE_TYPE_NAME].reader = read_name_table; - internal_data->table_info[OTF_TABLE_TYPE_CMAP].address = (void *) &otf->cmap; - internal_data->table_info[OTF_TABLE_TYPE_CMAP].reader = read_cmap_table; - internal_data->table_info[OTF_TABLE_TYPE_GDEF].address = (void *) &otf->gdef; - internal_data->table_info[OTF_TABLE_TYPE_GDEF].reader = read_gdef_table; - internal_data->table_info[OTF_TABLE_TYPE_GSUB].address = (void *) &otf->gsub; - internal_data->table_info[OTF_TABLE_TYPE_GSUB].reader = read_gsub_table; - internal_data->table_info[OTF_TABLE_TYPE_GPOS].address = (void *) &otf->gpos; - internal_data->table_info[OTF_TABLE_TYPE_GPOS].reader = read_gpos_table; - - head_tag = otf_tag ("head"); - name_tag = otf_tag ("name"); - cmap_tag = otf_tag ("cmap"); - gdef_tag = otf_tag ("GDEF"); - gsub_tag = otf_tag ("GSUB"); - gpos_tag = otf_tag ("GPOS"); - - stream = make_stream (); - if (! stream) - return -1; - - internal_data->header_stream = stream; - - /* Size of Offset Table is 12 bytes. */ - if (setup_stream (stream, fp, 0, 12, "Offset Table") < 0) - return -1; - if (read_offset_table (otf, stream, &otf->offset_table) < 0) - return -1; - - /* Size of each Table Directory is 16 bytes. */ - if (setup_stream (stream, fp, 12, 16 * otf->offset_table.numTables, - "Table Directory") < 0) - return -1; - - OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables, " (OffsetTable)"); - for (i = 0; i < otf->offset_table.numTables; i++) - { - OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i); - OTF_TableInfo *table_info = NULL; - - if (! tag) - return -1; - if (tag == head_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD; - else if (tag == name_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME; - else if (tag == cmap_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP; - else if (tag == gdef_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF; - else if (tag == gsub_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB; - else if (tag == gpos_tag) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS; - - if (table_info) - { - table_info->stream = make_stream (); - if (setup_stream (table_info->stream, fp, - otf->table_dirs[i].offset, - otf->table_dirs[i].length, - otf->table_dirs[i].name) < 0) - return -1; - } - } - - internal_data->header_stream = NULL; - free_stream (stream); - return 0; -} - - +/*** (1-2) "head" table */ static void * -read_head_table (OTF *otf, OTF_Stream *stream) +read_head_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { + OTF_Stream *stream = table->stream; char *errfmt = "head%s"; void *errret = NULL; OTF_head *head; @@ -403,184 +404,519 @@ read_head_table (OTF *otf, OTF_Stream *stream) READ_USHORT (stream, head->flags); READ_USHORT (stream, head->unitsPerEm); + *table->address = head; return head; } +/*** (1-3) "name" table */ static int -read_script_list (OTF *otf, OTF_Stream *stream, long offset, - OTF_ScriptList *list) +read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec) { - char *errfmt = "Script List%s"; + char errfmt[256]; int errret = -1; - int i, j, k; + OTF_StreamState state; + int ucs = 0; + int ascii = 0; + int i; - SEEK_STREAM (stream, offset); - READ_USHORT (stream, list->ScriptCount); - OTF_CALLOC (list->Script, list->ScriptCount, ""); + sprintf (errfmt, "nameID (%d)%%s", rec->nameID); + if (rec->platformID == 0) + ucs = (rec->encodingID <= 3) ? 2 : 4; + else if (rec->platformID == 1 && rec->encodingID == 0) + ascii = 1; + else if (rec->platformID == 3) + ucs = (rec->encodingID == 1 ? 2 + : rec->encodingID == 10 ? 4 + : 0); + + OTF_MALLOC (rec->name, rec->length + 1, ""); + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, stream->pos + rec->offset); + READ_BYTES (stream, rec->name, rec->length); + RESTORE_STREAM (stream, state); + rec->name[rec->length] = 0; - for (i = 0; i < list->ScriptCount; i++) + if (ascii) { - READ_TAG (stream, list->Script[i].ScriptTag); - READ_OFFSET (stream, list->Script[i].offset); + rec->ascii = 1; } - for (i = 0; i < list->ScriptCount; i++) + else if (ucs == 2) { - OTF_Script *script = list->Script + i; - long script_offset = offset + script->offset; - - SEEK_STREAM (stream, script_offset); - READ_OFFSET (stream, script->DefaultLangSysOffset); - READ_USHORT (stream, script->LangSysCount); - OTF_MALLOC (script->LangSysRecord, script->LangSysCount, " (LangSys)"); - OTF_CALLOC (script->LangSys, script->LangSysCount, " (LangSys)"); - for (j = 0; j < script->LangSysCount; j++) - { - READ_TAG (stream, script->LangSysRecord[j].LangSysTag); - READ_OFFSET (stream, script->LangSysRecord[j].LangSys); - } - - if (script->DefaultLangSysOffset) + rec->ascii = 1; + for (i = 0; i < rec->length / 2; i++) { - OTF_LangSys *langsys = &script->DefaultLangSys; - - SEEK_STREAM (stream, script_offset + script->DefaultLangSysOffset); - READ_OFFSET (stream, langsys->LookupOrder); - READ_USHORT (stream, langsys->ReqFeatureIndex); - READ_USHORT (stream, langsys->FeatureCount); - OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, - " (FeatureIndex)"); - for (k = 0; k < langsys->FeatureCount; k++) - READ_USHORT (stream, langsys->FeatureIndex[k]); + if (rec->name[i * 2] > 0 + || rec->name[i * 2 + 1] >= 128) + { + rec->ascii = 0; + break; + } } - - for (j = 0; j < script->LangSysCount; j++) + if (rec->ascii) + for (i = 0; i < rec->length / 2; i++) + rec->name[i] = rec->name[i * 2 + 1]; + rec->name[i] = 0; + } + else if (ucs == 4) + { + rec->ascii = 1; + for (i = 0; i < rec->length / 4; i++) { - OTF_LangSys *langsys = script->LangSys + j; - - SEEK_STREAM (stream, - script_offset + script->LangSysRecord[j].LangSys); - READ_OFFSET (stream, langsys->LookupOrder); - READ_USHORT (stream, langsys->ReqFeatureIndex); - READ_USHORT (stream, langsys->FeatureCount); - OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, - " (FeatureIndex)"); - for (k = 0; k < langsys->FeatureCount; k++) - READ_USHORT (stream, langsys->FeatureIndex[k]); + if (rec->name[i * 4] > 0 + || rec->name[i * 4 + 1] > 0 + || rec->name[i * 4 + 2] > 0 + || rec->name[i * 2 + 3] >= 128) + { + rec->ascii = 0; + break; + } } + if (rec->ascii) + for (i = 0; i < rec->length / 4; i++) + rec->name[i] = rec->name[i * 4 + 3]; + rec->name[i] = 0; } return 0; } -static int -read_feature_list (OTF *otf, OTF_Stream *stream, long offset, - OTF_FeatureList *list) +static void * +read_name_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { - char *errfmt = "Feature List%s"; - int errret = -1; - int i, j; + OTF_Stream *stream = table->stream; + char *errfmt = "name%s"; + void *errret = NULL; + OTF_name *name; + int i; - READ_UINT16 (stream, list->FeatureCount); - OTF_CALLOC (list->Feature, list->FeatureCount, ""); - for (i = 0; i < list->FeatureCount; i++) + OTF_CALLOC (name, 1, ""); + READ_USHORT (stream, name->format); + READ_USHORT (stream, name->count); + READ_USHORT (stream, name->stringOffset); + OTF_MALLOC (name->nameRecord, name->count, ""); + for (i = 0; i < name->count; i++) { - READ_TAG (stream, list->Feature[i].FeatureTag); - READ_OFFSET (stream, list->Feature[i].offset); + OTF_NameRecord *rec = name->nameRecord + i; + + READ_USHORT (stream, rec->platformID); + READ_USHORT (stream, rec->encodingID); + READ_USHORT (stream, rec->languageID); + READ_USHORT (stream, rec->nameID); + READ_USHORT (stream, rec->length); + READ_USHORT (stream, rec->offset); } - for (i = 0; i < list->FeatureCount; i++) + for (i = 0; i < name->count; i++) { - OTF_Feature *feature = list->Feature + i; + OTF_NameRecord *rec = name->nameRecord + i; + int nameID = rec->nameID; - SEEK_STREAM (stream, offset + feature->offset); - READ_OFFSET (stream, feature->FeatureParams); - READ_UINT16 (stream, feature->LookupCount); - OTF_MALLOC (feature->LookupListIndex, feature->LookupCount, - " (LookupListIndex)"); - for (j = 0; j < feature->LookupCount; j++) - READ_UINT16 (stream, feature->LookupListIndex[j]); + read_name (otf, stream, rec); + + if (nameID >= OTF_max_nameID) + continue; + if (! name->name[nameID] + && rec->ascii) + name->name[nameID] = (char *) rec->name; } - return 0; + *table->address = name; + return name; } -static int read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, - long offset, unsigned type, - OTF_LookupSubTableGSUB *subtable); -static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, - long offset, unsigned type, - OTF_LookupSubTableGPOS *subtable); + +/*** (1-4) "cmap" table */ -static int -read_lookup_list (OTF *otf, OTF_Stream *stream, long offset, - OTF_LookupList *list, int gsub) +static OTF_EncodingSubtable14 * +read_cmap_uvs_table (OTF *otf, OTF_Stream *stream, OTF_Offset offset) { - char *errfmt = "Lookup List%s"; - int errret = -1; - int i, j; - - SEEK_STREAM (stream, offset); - READ_UINT16 (stream, list->LookupCount); - OTF_CALLOC (list->Lookup, list->LookupCount, ""); - - for (i = 0; i < list->LookupCount; i++) - READ_OFFSET (stream, list->Lookup[i].offset); - for (i = 0; i < list->LookupCount; i++) + OTF_EncodingSubtable14 *sub14; + char *errfmt = "cmap-uvs%s"; + void *errret = NULL; + unsigned nRecords; + unsigned i,j; + + OTF_MALLOC (sub14, 1, " (EncodingSubtable14)"); + READ_ULONG (stream, nRecords); + sub14->nRecords = nRecords; + OTF_MALLOC (sub14->Records, nRecords, "(EncodingSubtable14-Records)"); + for (i = 0; i < sub14->nRecords; i++) { - OTF_Lookup *lookup = list->Lookup + i; + unsigned varSelector=0, defaultUVSOffset, nonDefaultUVSOffset; + + READ_UINT24 (stream, varSelector); + sub14->Records[i].varSelector = varSelector; + READ_ULONG (stream, defaultUVSOffset); + sub14->Records[i].defaultUVSOffset = defaultUVSOffset; + READ_ULONG (stream, nonDefaultUVSOffset); + sub14->Records[i].nonDefaultUVSOffset = nonDefaultUVSOffset; + } + for (i = 0; i < sub14->nRecords; i++) + { + OTF_VariationSelectorRecord *record = &sub14->Records[i]; + unsigned defaultUVSOffset = record->defaultUVSOffset; + unsigned nonDefaultUVSOffset = record->nonDefaultUVSOffset; - SEEK_STREAM (stream, offset + lookup->offset); - READ_UINT16 (stream, lookup->LookupType); - READ_UINT16 (stream, lookup->LookupFlag); - READ_UINT16 (stream, lookup->SubTableCount); - OTF_MALLOC (lookup->SubTableOffset, lookup->SubTableCount, - " (SubTableOffset)"); - if (gsub) - OTF_CALLOC (lookup->SubTable.gsub, lookup->SubTableCount, - " (SubTable)"); + if (defaultUVSOffset) + { + unsigned numUnicodeValueRanges; + + SEEK_STREAM (stream, offset+defaultUVSOffset); + READ_ULONG (stream, numUnicodeValueRanges); + record->numUnicodeValueRanges = numUnicodeValueRanges; + OTF_MALLOC (record->unicodeValueRanges, + numUnicodeValueRanges, + "(EncodingSubtable14-Records-unicodeValueRanges)"); + for (j = 0; j < numUnicodeValueRanges; j++) + { + OTF_UnicodeValueRange *unicodeValueRange + = &record->unicodeValueRanges[j]; + unsigned startUnicodeValue; + char additionalCount; + + READ_UINT24 (stream, startUnicodeValue); + unicodeValueRange->startUnicodeValue=startUnicodeValue; + READ_BYTES (stream, &additionalCount, 1); + unicodeValueRange->additionalCount + = (unsigned short) additionalCount; + } + } + if (nonDefaultUVSOffset) + { + unsigned numUVSMappings; + + SEEK_STREAM (stream, offset+nonDefaultUVSOffset); + READ_ULONG (stream, numUVSMappings); + record->numUVSMappings = numUVSMappings; + OTF_MALLOC (record->uvsMappings, numUVSMappings, + "(EncodingSubtable14-Records-uvsMappings)"); + for (j = 0; j < numUVSMappings; j++) + { + OTF_UVSMapping *uvsMapping = &record->uvsMappings[j]; + unsigned unicodeValue; + unsigned short glyphID; + + READ_UINT24 (stream, unicodeValue); + uvsMapping->unicodeValue = unicodeValue; + READ_USHORT (stream, glyphID); + uvsMapping->glyphID = glyphID; + } + } + } + return sub14; +} + +static void * +read_cmap_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) +{ + OTF_Stream *stream = table->stream; + char *errfmt = "cmap%s"; + void *errret = NULL; + OTF_cmap *cmap; + int unicode_bmp_index = -1, unicode_full_index = -1; + int i; + + OTF_CALLOC (cmap, 1, ""); + READ_USHORT (stream, cmap->version); + READ_USHORT (stream, cmap->numTables); + OTF_MALLOC (cmap->EncodingRecord, cmap->numTables, ""); + for (i = 0; i < cmap->numTables; i++) + { + unsigned platformID, encodingID; + + READ_USHORT (stream, platformID); + cmap->EncodingRecord[i].platformID = platformID; + READ_USHORT (stream, encodingID); + cmap->EncodingRecord[i].encodingID = encodingID; + READ_ULONG (stream, cmap->EncodingRecord[i].offset); + if (platformID == 0) + { + if (encodingID <= 3) + unicode_bmp_index = i; + else + unicode_full_index = i; + } + else if (platformID == 3) + { + if (encodingID == 1) + unicode_bmp_index = i; + else if (encodingID == 10) + unicode_full_index = i; + } + } + cmap->table_index = unicode_full_index; + + for (i = 0; i < cmap->numTables; i++) + { + unsigned format; + + SEEK_STREAM (stream, cmap->EncodingRecord[i].offset); + READ_USHORT (stream, format); + cmap->EncodingRecord[i].subtable.format = format; + if (format == 14) + { + READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length); + cmap->EncodingRecord[i].subtable.language = 0; + } else - OTF_CALLOC (lookup->SubTable.gpos, lookup->SubTableCount, - " (SubTable)"); - for (j = 0; j < lookup->SubTableCount; j++) - READ_OFFSET (stream, lookup->SubTableOffset[j]); - for (j = 0; j < lookup->SubTableCount; j++) { - long this_offset - = offset + lookup->offset + lookup->SubTableOffset[j]; + READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length); + if (format == 8 || format == 10 || format == 12) + { + READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length); + READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language); + } + else + { + READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language); + } + } + switch (format) + { + case 0: + { + OTF_MALLOC (cmap->EncodingRecord[i].subtable.f.f0, 1, + " (EncodingRecord)"); + READ_BYTES (stream, + cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray, + 256); + } + break; - if (gsub - ? read_lookup_subtable_gsub (otf, stream, this_offset, - lookup->LookupType, - lookup->SubTable.gsub + j) < 0 - : read_lookup_subtable_gpos (otf, stream, this_offset, - lookup->LookupType, - lookup->SubTable.gpos + j) < 0) - return errret; + case 2: + { + OTF_EncodingSubtable2 *sub2; + int j, max_key; + + OTF_MALLOC (sub2, 1, " (EncodingSubtable2)"); + cmap->EncodingRecord[i].subtable.f.f2 = sub2; + for (j = 0, max_key = 0; j < 256; j++) + { + READ_USHORT (stream, sub2->subHeaderKeys[j]); + if (max_key < sub2->subHeaderKeys[j]) + max_key = sub2->subHeaderKeys[j]; + } + max_key += 8; + sub2->subHeaderCount = max_key / 8; + OTF_MALLOC (sub2->subHeaders, max_key / 8, " (subHeaders)"); + for (j = 0; j < sub2->subHeaderCount; j++) + { + READ_USHORT (stream, sub2->subHeaders[j].firstCode); + READ_USHORT (stream, sub2->subHeaders[j].entryCount); + READ_SHORT (stream, sub2->subHeaders[j].idDelta); + READ_USHORT (stream, sub2->subHeaders[j].idRangeOffset); + /* Make it offset from sub2->glyphIndexArray. */ + sub2->subHeaders[j].idRangeOffset -= max_key - (j * 8 + 6); + } + sub2->glyphIndexCount = (cmap->EncodingRecord[i].subtable.length + - 262 - max_key); + OTF_MALLOC (sub2->glyphIndexArray, sub2->glyphIndexCount, + " (glyphIndexArray)"); + READ_BYTES (stream, sub2->glyphIndexArray, sub2->glyphIndexCount); + } + break; + + case 4: + { + OTF_EncodingSubtable4 *sub4; + int segCount; + int j; + unsigned dummy; + + OTF_MALLOC (sub4, 1, " (EncodingSubtable4)"); + cmap->EncodingRecord[i].subtable.f.f4 = sub4; + READ_USHORT (stream, sub4->segCountX2); + segCount = sub4->segCountX2 / 2; + READ_USHORT (stream, sub4->searchRange); + READ_USHORT (stream, sub4->entrySelector); + READ_USHORT (stream, sub4->rangeShift); + OTF_MALLOC (sub4->segments, segCount, " (segCount)"); + for (j = 0; j < segCount; j++) + READ_USHORT (stream, sub4->segments[j].endCount); + READ_USHORT (stream, dummy); + for (j = 0; j < segCount; j++) + READ_USHORT (stream, sub4->segments[j].startCount); + for (j = 0; j < segCount; j++) + READ_SHORT (stream, sub4->segments[j].idDelta); + for (j = 0; j < segCount; j++) + { + unsigned off; + unsigned rest = 2 * (segCount - j); + + READ_USHORT (stream, off); + if (off == 0) + sub4->segments[j].idRangeOffset = 0xFFFF; + else + sub4->segments[j].idRangeOffset = (off - rest) / 2; + } + j = (cmap->EncodingRecord[i].subtable.length + - (14 + 2 * (segCount * 4 + 1))); + sub4->GlyphCount = j / 2; + OTF_MALLOC (sub4->glyphIdArray, sub4->GlyphCount, " (GlyphCount)"); + for (j = 0; j < sub4->GlyphCount; j++) + READ_USHORT (stream, sub4->glyphIdArray[j]); + } + break; + + case 6: + { + OTF_EncodingSubtable6 *sub6; + int j; + + OTF_MALLOC (sub6, 1, " (EncodingSubtable6)"); + cmap->EncodingRecord[i].subtable.f.f6 = sub6; + READ_USHORT (stream, sub6->firstCode); + READ_USHORT (stream, sub6->entryCount); + OTF_MALLOC (sub6->glyphIdArray, sub6->entryCount, " (GlyphCount)"); + for (j = 0; j < sub6->entryCount; j++) + READ_USHORT (stream, sub6->glyphIdArray[j]); + } + break; + + case 8: + { + OTF_EncodingSubtable8 *sub8; + int j; + + OTF_MALLOC (sub8, 1, " (EncodingSubtable8)"); + cmap->EncodingRecord[i].subtable.f.f8 = sub8; + for (j = 0; j < 8192; j++) + READ_BYTES (stream, sub8->is32, 8192); + READ_ULONG (stream, sub8->nGroups); + OTF_MALLOC (sub8->Groups, sub8->nGroups, " (Groups)"); + for (j = 0; j < sub8->nGroups; j++) + { + READ_ULONG (stream, sub8->Groups[i].startCharCode); + READ_ULONG (stream, sub8->Groups[i].endCharCode); + READ_ULONG (stream, sub8->Groups[i].startGlyphID); + } + } + break; + + case 10: + { + OTF_EncodingSubtable10 *sub10; + int j; + + OTF_MALLOC (sub10, 1, " (EncodingSubtable10)"); + cmap->EncodingRecord[i].subtable.f.f10 = sub10; + READ_ULONG (stream, sub10->startCharCode); + READ_ULONG (stream, sub10->numChars); + OTF_MALLOC (sub10->glyphs, sub10->numChars, " (GlyphCount)"); + for (j = 0; j < sub10->numChars; j++) + READ_USHORT (stream, sub10->glyphs[j]); + } + break; + + case 12: + { + OTF_EncodingSubtable12 *sub12; + int j; + + OTF_MALLOC (sub12, 1, " (EncodingSubtable12)"); + cmap->EncodingRecord[i].subtable.f.f12 = sub12; + READ_ULONG (stream, sub12->nGroups); + OTF_MALLOC (sub12->Groups, sub12->nGroups, " (Groups)"); + for (j = 0; j < sub12->nGroups; j++) + { + READ_ULONG (stream, sub12->Groups[j].startCharCode); + READ_ULONG (stream, sub12->Groups[j].endCharCode); + READ_ULONG (stream, sub12->Groups[j].startGlyphID); + } + } + break; + + case 14: + { + cmap->EncodingRecord[i].subtable.f.f14 + = read_cmap_uvs_table (otf, stream, + cmap->EncodingRecord[i].offset); + break; + } + + default: + OTF_ERROR (OTF_ERROR_TABLE, " (invalid Subtable format)"); } } - return 0; + if (unicode_bmp_index >= 0) + { + OTF_EncodingRecord *rec = cmap->EncodingRecord + unicode_bmp_index; + OTF_GlyphID glyph_id, max_glyph_id = 0; + + OTF_CALLOC (cmap->unicode_table, 0x10000, ""); + switch (rec->subtable.format) + { + case 4: + { + OTF_EncodingSubtable4 *sub4 = rec->subtable.f.f4; + int segCount = sub4->segCountX2 / 2; + + for (i = 0; i < segCount; i++) + { + OTF_cmapSegment *seg = sub4->segments + i; + int c; + + if (seg->idRangeOffset == 0xFFFF) + for (c = seg->startCount; c <= seg->endCount; c++) + { + glyph_id = (c + seg->idDelta) % 0x10000; + cmap->unicode_table[c] = glyph_id; + if (glyph_id > max_glyph_id) + max_glyph_id = glyph_id; + } + else + for (c = seg->startCount; c <= seg->endCount && c != 0xFFFF; + c++) + { + glyph_id = sub4->glyphIdArray[seg->idRangeOffset + + (c - seg->startCount)]; + cmap->unicode_table[c] = glyph_id; + if (glyph_id > max_glyph_id) + max_glyph_id = glyph_id; + } + } + } + } + + OTF_CALLOC (cmap->decode_table, max_glyph_id + 1, ""); + for (i = 0; i < 0x10000; i++) + if (cmap->unicode_table[i]) + cmap->decode_table[cmap->unicode_table[i]] = i; + cmap->max_glyph_id = max_glyph_id; + } + + *table->address = cmap; + return cmap; } + +/*** (1-5) Structures common to GDEF, GSUB, and GPOS */ + +/* Read Glyph-IDs from STREAM. Allocate memory for IDS, and store the + Glyph-IDs there. If COUNT is negative, read the number of + Glyphs-IDs at first. MINUS if nozero is how few the actual + Glyph-IDs are in STREAM than COUNT. */ static int -read_glyph_ids (OTF *otf, OTF_Stream *stream, OTF_GlyphID **ids, int minus) +read_glyph_ids (OTF *otf, OTF_Stream *stream, OTF_GlyphID **ids, + int minus, int count) { char *errfmt = "GlyphID List%s"; int errret = -1; - unsigned count; int i; - READ_UINT16 (stream, count); + if (count < 0) + READ_UINT16 (stream, count); if (! count) return 0; OTF_MALLOC (*ids, count, ""); for (i = 0; i < count + minus; i++) READ_GLYPHID (stream, (*ids)[i]); - return (int) count; + return count; } - + static unsigned read_range_records (OTF *otf, OTF_Stream *stream, OTF_RangeRecord **record) { @@ -611,13 +947,13 @@ read_coverage (OTF *otf, OTF_Stream *stream, long offset, int errret = -1; OTF_StreamState state; int count; - + READ_OFFSET (stream, coverage->offset); SAVE_STREAM (stream, state); SEEK_STREAM (stream, offset + coverage->offset); READ_UINT16 (stream, coverage->CoverageFormat); if (coverage->CoverageFormat == 1) - count = read_glyph_ids (otf, stream, &coverage->table.GlyphArray, 0); + count = read_glyph_ids (otf, stream, &coverage->table.GlyphArray, 0, -1); else if (coverage->CoverageFormat == 2) count = read_range_records (otf, stream, &coverage->table.RangeRecord); else @@ -629,16 +965,20 @@ read_coverage (OTF *otf, OTF_Stream *stream, long offset, return 0; } +/* Read list of Coverages from STREAM. Allocate memory for COVERAGE, + and store the Coverages there. If COUNT is negative, read the + number of Coverages at first. */ + static int read_coverage_list (OTF *otf, OTF_Stream *stream, long offset, - OTF_Coverage **coverage) + OTF_Coverage **coverage, int count) { char *errfmt = "Coverage List%s"; int errret = -1; - int count; int i; - READ_UINT16 (stream, count); + if (count < 0) + READ_UINT16 (stream, count); if (! count) return 0; OTF_MALLOC (*coverage, count, ""); @@ -663,7 +1003,7 @@ read_class_def_without_offset (OTF *otf, OTF_Stream *stream, READ_GLYPHID (stream, class->f.f1.StartGlyph); class->f.f1.GlyphCount = (read_glyph_ids - (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0)); + (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0, -1)); if (! class->f.f1.GlyphCount) OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); } @@ -687,8 +1027,10 @@ read_class_def (OTF *otf, OTF_Stream *stream, long offset, OTF_ClassDef *class) char *errfmt = "ClassDef%s"; int errret = -1; OTF_StreamState state; - + READ_OFFSET (stream, class->offset); + if (! class->offset) + return 0; SAVE_STREAM (stream, state); SEEK_STREAM (stream, offset + class->offset); READ_UINT16 (stream, class->ClassFormat); @@ -696,16 +1038,18 @@ read_class_def (OTF *otf, OTF_Stream *stream, long offset, OTF_ClassDef *class) { READ_GLYPHID (stream, class->f.f1.StartGlyph); class->f.f1.GlyphCount - = (read_glyph_ids - (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0)); + = read_glyph_ids (otf, stream, + (OTF_GlyphID **) &class->f.f1.ClassValueArray, + 0, -1); if (! class->f.f1.GlyphCount) return -1; } else if (class->ClassFormat == 2) { class->f.f2.ClassRangeCount - = (read_range_records - (otf, stream, (OTF_RangeRecord **) &class->f.f2.ClassRangeRecord)); + = read_range_records (otf, stream, + (OTF_RangeRecord **) + &class->f.f2.ClassRangeRecord); if (! class->f.f2.ClassRangeCount) return -1; } @@ -737,177 +1081,520 @@ read_device_table (OTF *otf, OTF_Stream *stream, long offset, READ_UINT16 (stream, table->EndSize); READ_UINT16 (stream, table->DeltaFormat); num = table->EndSize - table->StartSize + 1; - OTF_MALLOC (table->DeltaValue, num, ""); + if (num > 0 && table->DeltaFormat >= 1 && table->DeltaFormat <= 3) + { + OTF_MALLOC (table->DeltaValue, num, ""); - if (table->DeltaFormat == 1) - for (i = 0; i < num; i++) - { - if ((i % 8) == 0) - READ_UINT16 (stream, val); - intval.int2 = (val >> (14 - (i % 8) * 2)) & 0x03; - table->DeltaValue[i] = intval.int2; - } - else if (table->DeltaFormat == 2) - for (i = 0; i < num; i++) - { - if ((i % 4) == 0) - READ_UINT16 (stream, val); - intval.int4 = (val >> (12 - (i % 4) * 4)) & 0x0F; - table->DeltaValue[i] = intval.int4; - } - else if (table->DeltaFormat == 3) - for (i = 0; i < num; i++) - { - if ((i % 2) == 0) + if (table->DeltaFormat == 1) + for (i = 0; i < num; i++) { - READ_UINT16 (stream, val); - intval.int8 = val >> 8; - table->DeltaValue[i] = intval.int8; + if ((i % 8) == 0) + READ_UINT16 (stream, val); + intval.int2 = (val >> (14 - (i % 8) * 2)) & 0x03; + table->DeltaValue[i] = intval.int2; } - else + else if (table->DeltaFormat == 2) + for (i = 0; i < num; i++) { - intval.int8 = val >> 8; - table->DeltaValue[i] = intval.int8; + if ((i % 4) == 0) + READ_UINT16 (stream, val); + intval.int4 = (val >> (12 - (i % 4) * 4)) & 0x0F; + table->DeltaValue[i] = intval.int4; } - } + else /* (table->DeltaFormat == 3) */ + for (i = 0; i < num; i++) + { + if ((i % 2) == 0) + { + READ_UINT16 (stream, val); + intval.int8 = val >> 8; + table->DeltaValue[i] = intval.int8; + } + else + { + intval.int8 = val >> 8; + table->DeltaValue[i] = intval.int8; + } + } + } else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); + { + /* Invalid DeltaFormat but several fonts has such values (bug of + fontforge?). So accept it with NULL delta values. */ + table->DeltaValue = NULL; + } return 0; } -/* GSUB */ - -static void * -read_gsub_table (OTF *otf, OTF_Stream *stream) -{ - char *errfmt = "GSUB%s"; - void *errret = NULL; - OTF_GSUB *gsub; - - OTF_CALLOC (gsub, 1, ""); - READ_FIXED (stream, gsub->Version); - READ_OFFSET (stream, gsub->ScriptList.offset); - READ_OFFSET (stream, gsub->FeatureList.offset); - READ_OFFSET (stream, gsub->LookupList.offset); - - if (read_script_list (otf, stream, gsub->ScriptList.offset, - &gsub->ScriptList) < 0 - || read_feature_list (otf, stream, gsub->FeatureList.offset, - &gsub->FeatureList) < 0 - || read_lookup_list (otf, stream, gsub->LookupList.offset, - &gsub->LookupList, 1) < 0) - return NULL; - return gsub; -} +/*** (1-6) "GDEF" table */ -static unsigned -read_sequence (OTF *otf, OTF_Stream *stream, long offset, OTF_Sequence **seq) +static int +read_attach_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_AttachList *list) { - char *errfmt = "Sequence%s"; - unsigned errret = 0; - unsigned count; - int i; + char *errfmt = "AttachList%s"; + int errret = -1; + int i, j; - READ_UINT16 (stream, count); - OTF_MALLOC (*seq, count, ""); - if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*seq)[i].offset); - for (i = 0; i < count; i++) + if (read_coverage (otf, stream, offset, &list->Coverage) < 0) + return -1; + READ_UINT16 (stream, list->GlyphCount); + OTF_MALLOC (list->AttachPoint, list->GlyphCount, ""); + for (i = 0; i < list->GlyphCount; i++) + READ_OFFSET (stream, list->AttachPoint[i].offset); + for (i = 0; i < list->GlyphCount; i++) { - SEEK_STREAM (stream, offset + (*seq)[i].offset); - (*seq)[i].GlyphCount = read_glyph_ids (otf, stream, - &(*seq)[i].Substitute, 0); - if (! (*seq)[i].GlyphCount) - return 0; + int count; + + SEEK_STREAM (stream, offset + list->AttachPoint[i].offset); + READ_UINT16 (stream, count); + list->AttachPoint[i].PointCount = count; + OTF_MALLOC (list->AttachPoint[i].PointIndex, count, " (PointIndex)"); + for (j = 0; j < count; j++) + READ_UINT16 (stream, list->AttachPoint[i].PointIndex[j]); } - return count; + return 0; } static int -read_ligature (OTF *otf, OTF_Stream *stream, long offset, - OTF_Ligature **ligature) +read_caret_value (OTF *otf, OTF_Stream *stream, long offset, + OTF_CaretValue *caret) { - char *errfmt = "Ligature%s"; + char *errfmt = "CaretValue%s"; int errret = -1; - int count; - int i; - READ_UINT16 (stream, count); - if (! count) - return 0; - OTF_MALLOC (*ligature, count, ""); - for (i = 0; i < count; i++) - READ_OFFSET (stream, (*ligature)[i].offset); - for (i = 0; i < count; i++) + SEEK_STREAM (stream, offset + caret->offset); + READ_UINT16 (stream, caret->CaretValueFormat); + if (caret->CaretValueFormat == 1) + READ_INT16 (stream, caret->f.f1.Coordinate); + else if (caret->CaretValueFormat == 2) + READ_UINT16 (stream, caret->f.f2.CaretValuePoint); + else if (caret->CaretValueFormat == 3) { - SEEK_STREAM (stream, offset + (*ligature)[i].offset); - READ_GLYPHID (stream, (*ligature)[i].LigGlyph); - (*ligature)[i].CompCount - = read_glyph_ids (otf, stream, &(*ligature)[i].Component, -1); - if (! (*ligature)[i].CompCount) + READ_INT16 (stream, caret->f.f3.Coordinate); + if (read_device_table (otf, stream, offset + caret->offset, + &caret->f.f3.DeviceTable) < 0) return -1; } - return count; + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); + return 0; } static int -read_ligature_set (OTF *otf, OTF_Stream *stream, long offset, - OTF_LigatureSet **ligset) +read_lig_caret_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_LigCaretList *list) { - char *errfmt = "LigatureSet%s"; + char *errfmt = "LigCaretList%s"; int errret = -1; - int count; + int i, j; + + if (read_coverage (otf, stream, offset, &list->Coverage) < 0) + return -1; + READ_UINT16 (stream, list->LigGlyphCount); + OTF_MALLOC (list->LigGlyph, list->LigGlyphCount, ""); + for (i = 0; i < list->LigGlyphCount; i++) + READ_OFFSET (stream, list->LigGlyph[i].offset); + for (i = 0; i < list->LigGlyphCount; i++) + { + int count; + + SEEK_STREAM (stream, offset + list->LigGlyph[i].offset); + READ_UINT16 (stream, count); + list->LigGlyph[i].CaretCount = count; + OTF_MALLOC (list->LigGlyph[i].CaretValue, count, " (CaretValue)"); + for (j = 0; j < count; j++) + READ_OFFSET (stream, list->LigGlyph[i].CaretValue[j].offset); + for (j = 0; j < count; j++) + if (read_caret_value (otf, stream, offset + list->LigGlyph[i].offset, + &list->LigGlyph[i].CaretValue[j]) < 0) + return -1; + } + return 0; +} + +static int +read_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header) +{ + int errret = -1; + + READ_FIXED (stream, header->Version); + READ_OFFSET (stream, header->GlyphClassDef); + READ_OFFSET (stream, header->AttachList); + READ_OFFSET (stream, header->LigCaretList); + READ_OFFSET (stream, header->MarkAttachClassDef); + return 0; +} + +static void * +read_gdef_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) +{ + OTF_Stream *stream = table->stream; + char *errfmt = "GDEF%s"; + void *errret = NULL; + OTF_GDEF *gdef; + + OTF_CALLOC (gdef, 1, ""); + if (stream->buf) + { + read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header); + if (gdef->header.GlyphClassDef) + { + gdef->glyph_class_def.offset = gdef->header.GlyphClassDef; + read_class_def_without_offset (otf, stream, + &gdef->glyph_class_def); + } + if (gdef->header.AttachList) + read_attach_list (otf, stream, gdef->header.AttachList, + &gdef->attach_list); + if (gdef->header.LigCaretList) + read_lig_caret_list (otf, stream, gdef->header.LigCaretList, + &gdef->lig_caret_list); + if (gdef->header.MarkAttachClassDef) + { + gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef; + read_class_def_without_offset (otf, stream, + &gdef->mark_attach_class_def); + } + } + + *table->address = gdef; + return gdef; +} + + +/*** (1-7) Structures for ScriptList, FeatureList, and LookupList */ + +static int +read_script_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ScriptList *list) +{ + char *errfmt = "Script List%s"; + int errret = -1; + int i, j, k; + + SEEK_STREAM (stream, offset); + READ_USHORT (stream, list->ScriptCount); + OTF_CALLOC (list->Script, list->ScriptCount, ""); + + for (i = 0; i < list->ScriptCount; i++) + { + READ_TAG (stream, list->Script[i].ScriptTag); + READ_OFFSET (stream, list->Script[i].offset); + } + for (i = 0; i < list->ScriptCount; i++) + { + OTF_Script *script = list->Script + i; + long script_offset = offset + script->offset; + + SEEK_STREAM (stream, script_offset); + READ_OFFSET (stream, script->DefaultLangSysOffset); + READ_USHORT (stream, script->LangSysCount); + OTF_MALLOC (script->LangSysRecord, script->LangSysCount, " (LangSys)"); + OTF_CALLOC (script->LangSys, script->LangSysCount, " (LangSys)"); + for (j = 0; j < script->LangSysCount; j++) + { + READ_TAG (stream, script->LangSysRecord[j].LangSysTag); + READ_OFFSET (stream, script->LangSysRecord[j].LangSys); + } + + if (script->DefaultLangSysOffset) + { + OTF_LangSys *langsys = &script->DefaultLangSys; + + SEEK_STREAM (stream, script_offset + script->DefaultLangSysOffset); + READ_OFFSET (stream, langsys->LookupOrder); + READ_USHORT (stream, langsys->ReqFeatureIndex); + READ_USHORT (stream, langsys->FeatureCount); + OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, + " (FeatureIndex)"); + for (k = 0; k < langsys->FeatureCount; k++) + READ_USHORT (stream, langsys->FeatureIndex[k]); + } + + for (j = 0; j < script->LangSysCount; j++) + { + OTF_LangSys *langsys = script->LangSys + j; + + SEEK_STREAM (stream, + script_offset + script->LangSysRecord[j].LangSys); + READ_OFFSET (stream, langsys->LookupOrder); + READ_USHORT (stream, langsys->ReqFeatureIndex); + READ_USHORT (stream, langsys->FeatureCount); + OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount, + " (FeatureIndex)"); + for (k = 0; k < langsys->FeatureCount; k++) + READ_USHORT (stream, langsys->FeatureIndex[k]); + } + } + + return 0; +} + +static int +read_feature_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_FeatureList *list) +{ + char *errfmt = "Feature List%s"; + int errret = -1; + int i, j; + + SEEK_STREAM (stream, offset); + READ_UINT16 (stream, list->FeatureCount); + OTF_CALLOC (list->Feature, list->FeatureCount, ""); + for (i = 0; i < list->FeatureCount; i++) + { + READ_TAG (stream, list->Feature[i].FeatureTag); + READ_OFFSET (stream, list->Feature[i].offset); + } + for (i = 0; i < list->FeatureCount; i++) + { + OTF_Feature *feature = list->Feature + i; + + SEEK_STREAM (stream, offset + feature->offset); + READ_OFFSET (stream, feature->FeatureParams); + READ_UINT16 (stream, feature->LookupCount); + OTF_MALLOC (feature->LookupListIndex, feature->LookupCount, + " (LookupListIndex)"); + for (j = 0; j < feature->LookupCount; j++) + READ_UINT16 (stream, feature->LookupListIndex[j]); + } + + return 0; +} + +static int read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, + long offset, unsigned type, + OTF_LookupSubTableGSUB *subtable); +static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, + long offset, unsigned type, + OTF_LookupSubTableGPOS *subtable); + +static int +read_lookup_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_LookupList *list, int gsubp) +{ + char *errfmt = "Lookup List%s"; + int errret = -1; + int i, j; + + SEEK_STREAM (stream, offset); + READ_UINT16 (stream, list->LookupCount); + OTF_CALLOC (list->Lookup, list->LookupCount, ""); + + for (i = 0; i < list->LookupCount; i++) + READ_OFFSET (stream, list->Lookup[i].offset); + for (i = 0; i < list->LookupCount; i++) + { + OTF_Lookup *lookup = list->Lookup + i; + + SEEK_STREAM (stream, offset + lookup->offset); + READ_UINT16 (stream, lookup->LookupType); + READ_UINT16 (stream, lookup->LookupFlag); + READ_UINT16 (stream, lookup->SubTableCount); + OTF_MALLOC (lookup->SubTableOffset, lookup->SubTableCount, + " (SubTableOffset)"); + if (gsubp) + OTF_CALLOC (lookup->SubTable.gsub, lookup->SubTableCount, + " (SubTable)"); + else + OTF_CALLOC (lookup->SubTable.gpos, lookup->SubTableCount, + " (SubTable)"); + for (j = 0; j < lookup->SubTableCount; j++) + READ_OFFSET (stream, lookup->SubTableOffset[j]); + for (j = 0; j < lookup->SubTableCount; j++) + { + long this_offset + = offset + lookup->offset + lookup->SubTableOffset[j]; + + if (gsubp + ? read_lookup_subtable_gsub (otf, stream, this_offset, + lookup->LookupType, + lookup->SubTable.gsub + j) < 0 + : read_lookup_subtable_gpos (otf, stream, this_offset, + lookup->LookupType, + lookup->SubTable.gpos + j) < 0) + return errret; + } + } + + return 0; +} + + +/*** (1-8) Structures common to GSUB and GPOS */ + +static unsigned +read_lookup_record_list (OTF *otf, OTF_Stream *stream, + OTF_LookupRecord **record, int count) +{ + char *errfmt = "LookupRecord%s"; + unsigned errret = 0; + int i; + + if (count < 0) + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*record, count, ""); + for (i = 0; i < count; i++) + { + READ_UINT16 (stream, (*record)[i].SequenceIndex); + READ_UINT16 (stream, (*record)[i].LookupListIndex); + } + return count; +} + +static unsigned +read_rule_list (OTF *otf, OTF_Stream *stream, long offset, OTF_Rule **rule) +{ + char *errfmt = "List of Rule%s"; + unsigned errret = 0; + OTF_StreamState state; + unsigned count; int i; READ_UINT16 (stream, count); if (! count) - return 0; - OTF_MALLOC (*ligset, count, ""); + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*rule, count, ""); for (i = 0; i < count; i++) - READ_OFFSET (stream, (*ligset)[i].offset); + { + READ_OFFSET (stream, (*rule)[i].offset); + if (! (*rule)[i].offset) + OTF_ERROR (OTF_ERROR_TABLE, " (zero offset)"); + } + SAVE_STREAM (stream, state); for (i = 0; i < count; i++) { - int lig_count; + SEEK_STREAM (stream, offset + (*rule)[i].offset); + READ_UINT16 (stream, (*rule)[i].GlyphCount); + if ((*rule)[i].GlyphCount == 0) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + READ_UINT16 (stream, (*rule)[i].LookupCount); + if (read_glyph_ids (otf, stream, &(*rule)[i].Input, 0, + (*rule)[i].GlyphCount) < 0) + return errret; + if (read_lookup_record_list (otf, stream, &(*rule)[i].LookupRecord, + (*rule)[i].LookupCount) == 0) + return errret; + } + RESTORE_STREAM (stream, state); + return count; +} - SEEK_STREAM (stream, offset + (*ligset)[i].offset); - lig_count = read_ligature (otf, stream, offset + (*ligset)[i].offset, - &(*ligset)[i].Ligature); - if (lig_count < 0) - return -1; - (*ligset)[i].LigatureCount = (unsigned) lig_count; + +static unsigned +read_rule_set_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_RuleSet **set) +{ + char *errfmt = "List of RuleSet%s"; + unsigned errret = 0; + OTF_StreamState state; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*set, count, ""); + for (i = 0; i < count; i++) + { + READ_OFFSET (stream, (*set)[i].offset); + if (! (*set)[i].offset) + OTF_ERROR (OTF_ERROR_TABLE, " (zero offset)"); } + SAVE_STREAM (stream, state); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*set)[i].offset); + (*set)[i].RuleCount + = read_rule_list (otf, stream, offset + (*set)[i].offset, + &(*set)[i].Rule); + if (! (*set)[i].RuleCount) + return errret; + } + RESTORE_STREAM (stream, state); return count; } static unsigned -read_subst_lookup_record (OTF *otf, OTF_Stream *stream, - OTF_SubstLookupRecord **record) +read_class_rule_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ClassRule **rule) { - char *errfmt = "SubstLookupRecord%s"; + char *errfmt = "ClassRule%s"; unsigned errret = 0; + OTF_StreamState state; unsigned count; int i; READ_UINT16 (stream, count); if (! count) OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*record, count, ""); + OTF_MALLOC (*rule, count, ""); for (i = 0; i < count; i++) { - READ_UINT16 (stream, (*record)[i].SequenceIndex); - READ_UINT16 (stream, (*record)[i].LookupListIndex); + READ_OFFSET (stream, (*rule)[i].offset); + if (! (*rule)[i].offset) + OTF_ERROR (OTF_ERROR_TABLE, " (zero offset)"); } + SAVE_STREAM (stream, state); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*rule)[i].offset); + READ_USHORT (stream, (*rule)[i].GlyphCount); + if (! (*rule)[i].GlyphCount) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + READ_USHORT (stream, (*rule)[i].LookupCount); + if (read_glyph_ids (otf, stream, (OTF_GlyphID **) &(*rule)[i].Class, + 0, (*rule)[i].GlyphCount - 1) < 0) + return errret; + if (read_lookup_record_list (otf, stream, &(*rule)[i].LookupRecord, + (*rule)[i].LookupCount) == 0) + return errret; + } + RESTORE_STREAM (stream, state); return count; } static unsigned -read_chain_subrule (OTF *otf, OTF_Stream *stream, long offset, - OTF_ChainSubRule **rule) +read_class_set_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ClassSet **set) { - char *errfmt = "ChainSubRule%s"; + char *errfmt = "ClassSet%s"; + unsigned errret = 0; + OTF_StreamState state; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_CALLOC (*set, count, ""); + for (i = 0; i < count; i++) + /* Offset can be zero. */ + READ_OFFSET (stream, (*set)[i].offset); + SAVE_STREAM (stream, state); + for (i = 0; i < count; i++) + if ((*set)[i].offset) + { + SEEK_STREAM (stream, offset + (*set)[i].offset); + (*set)[i].ClassRuleCnt + = read_class_rule_list (otf, stream, offset + (*set)[i].offset, + &(*set)[i].ClassRule); + if (! (*set)[i].ClassRuleCnt) + return errret; + } + RESTORE_STREAM (stream, state); + return count; +} + +static unsigned +read_chain_rule_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainRule **rule) +{ + char *errfmt = "ChainRule%s"; unsigned errret = 0; unsigned count; int i; @@ -922,32 +1609,106 @@ read_chain_subrule (OTF *otf, OTF_Stream *stream, long offset, { SEEK_STREAM (stream, offset + (*rule)[i].offset); (*rule)[i].BacktrackGlyphCount - = read_glyph_ids (otf, stream, &(*rule)[i].Backtrack, 0); - if (! (*rule)[i].BacktrackGlyphCount) - return 0; + = read_glyph_ids (otf, stream, &(*rule)[i].Backtrack, 0, -1); (*rule)[i].InputGlyphCount - = read_glyph_ids (otf, stream, &(*rule)[i].Input, -1); + = read_glyph_ids (otf, stream, &(*rule)[i].Input, -1, -1); if (! (*rule)[i].InputGlyphCount) - return 0; + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); (*rule)[i].LookaheadGlyphCount - = read_glyph_ids (otf, stream, &(*rule)[i].LookAhead, 0); - if (! (*rule)[i].LookaheadGlyphCount) - return 0; - (*rule)[i].SubstCount - = read_subst_lookup_record (otf, stream, &(*rule)[i].SubstLookupRecord); - if (! (*rule)[i].SubstCount) - return 0; + = read_glyph_ids (otf, stream, &(*rule)[i].LookAhead, 0, -1); + (*rule)[i].LookupCount + = read_lookup_record_list (otf, stream, + &(*rule)[i].LookupRecord, -1); + if (! (*rule)[i].LookupCount) + return errret; } return count; } static unsigned -read_chain_subrule_set (OTF *otf, OTF_Stream *stream, long offset, - OTF_ChainSubRuleSet **set) +read_chain_rule_set_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainRuleSet **set) +{ + char *errfmt = "ChainRuleSet%s"; + unsigned errret = 0; + OTF_StreamState state; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*set, count, ""); + for (i = 0; i < count; i++) + { + READ_OFFSET (stream, (*set)[i].offset); + if (! (*set)[i].offset) + OTF_ERROR (OTF_ERROR_TABLE, " (zero offset)"); + } + SAVE_STREAM (stream, state); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*set)[i].offset); + (*set)[i].ChainRuleCount + = read_chain_rule_list (otf, stream, offset + (*set)[i].offset, + &(*set)[i].ChainRule); + if (! (*set)[i].ChainRuleCount) + return errret; + } + RESTORE_STREAM (stream, state); + return count; +} + +static unsigned +read_chain_class_rule_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainClassRule **rule) +{ + char *errfmt = "ChainClassRule%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*rule, count, ""); + for (i = 0; i < count; i++) + { + READ_OFFSET (stream, (*rule)[i].offset); + if (! (*rule)[i].offset) + OTF_ERROR (OTF_ERROR_TABLE, " (zero offset)"); + } + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*rule)[i].offset); + (*rule)[i].BacktrackGlyphCount + = read_glyph_ids (otf, stream, + (OTF_GlyphID **) &(*rule)[i].Backtrack, 0, -1); + (*rule)[i].InputGlyphCount + = read_glyph_ids (otf, stream, + (OTF_GlyphID **) &(*rule)[i].Input, -1, -1); + if (! (*rule)[i].InputGlyphCount) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + (*rule)[i].LookaheadGlyphCount + = read_glyph_ids (otf, stream, + (OTF_GlyphID **) &(*rule)[i].LookAhead, 0, -1); + (*rule)[i].LookupCount + = read_lookup_record_list (otf, stream, + &(*rule)[i].LookupRecord, -1); + if (! (*rule)[i].LookupCount) + return errret; + } + return count; +} + +static unsigned +read_chain_class_set_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_ChainClassSet **set) { - char *errfmt = "ChainSubRuleSet%s"; + char *errfmt = "ChainClassSet%s"; unsigned errret = 0; + OTF_StreamState state; unsigned count; int i; @@ -956,96 +1717,322 @@ read_chain_subrule_set (OTF *otf, OTF_Stream *stream, long offset, OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); OTF_MALLOC (*set, count, ""); for (i = 0; i < count; i++) + /* Offset may be zero. */ READ_OFFSET (stream, (*set)[i].offset); + SAVE_STREAM (stream, state); + for (i = 0; i < count; i++) + if ((*set)[i].offset) + { + SEEK_STREAM (stream, offset + (*set)[i].offset); + (*set)[i].ChainClassRuleCnt + = read_chain_class_rule_list (otf, stream, offset + (*set)[i].offset, + &(*set)[i].ChainClassRule); + if (! (*set)[i].ChainClassRuleCnt) + return errret; + } + RESTORE_STREAM (stream, state); + return count; +} + +static int +read_context1 (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage,OTF_Context1 *context1) +{ + if (read_coverage (otf, stream, offset, coverage) < 0) + return -1; + context1->RuleSetCount + = read_rule_set_list (otf, stream, offset, &context1->RuleSet); + if (! context1->RuleSetCount) + return -1; + return 0; +} + +static int +read_context2 (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage,OTF_Context2 *context2) +{ + if (read_coverage (otf, stream, offset, coverage) < 0 + || read_class_def (otf, stream, offset, &context2->ClassDef) < 0) + return -1; + context2->ClassSetCnt + = read_class_set_list (otf, stream, offset, &context2->ClassSet); + if (! context2->ClassSetCnt) + return -1; + return 0; +} + +static int +read_context3 (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage,OTF_Context3 *context3) +{ + char *errfmt = "Context1%s"; + int errret = -1; + + READ_USHORT (stream, context3->GlyphCount); + if (context3->GlyphCount < 0) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + READ_USHORT (stream, context3->LookupCount); + if (read_coverage_list (otf, stream, offset, &context3->Coverage, + context3->GlyphCount) < 0) + return errret; + if (read_lookup_record_list (otf, stream, &context3->LookupRecord, + context3->LookupCount) < 0) + return errret; + return 0; +} + +static int +read_chain_context1 (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage, OTF_ChainContext1 *chain_context1) +{ + if (read_coverage (otf, stream, offset, coverage) < 0) + return -1; + chain_context1->ChainRuleSetCount + = read_chain_rule_set_list (otf, stream, offset, + &chain_context1->ChainRuleSet); + if (! chain_context1->ChainRuleSetCount) + return -1; + return 0; +} + +static int +read_chain_context2 (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage, OTF_ChainContext2 *chain_context2) +{ + if (read_coverage (otf, stream, offset, coverage) < 0 + || read_class_def (otf, stream, offset, + &chain_context2->BacktrackClassDef) < 0 + || read_class_def (otf, stream, offset, + &chain_context2->InputClassDef) < 0 + || read_class_def (otf, stream, offset, + &chain_context2->LookaheadClassDef) < 0) + return -1; + chain_context2->ChainClassSetCnt + = read_chain_class_set_list (otf, stream, offset, + &chain_context2->ChainClassSet); + if (! chain_context2->ChainClassSetCnt) + return -1; + return 0; +} + +static int +read_chain_context3 (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage, OTF_ChainContext3 *chain_context3) +{ + int count; + + count = read_coverage_list (otf, stream, offset, + &chain_context3->Backtrack, -1); + if (count < 0) + return -1; + chain_context3->BacktrackGlyphCount = (unsigned) count; + count = read_coverage_list (otf, stream, offset, + &chain_context3->Input, -1); + if (count <= 0) + return -1; + chain_context3->InputGlyphCount = (unsigned) count; + *coverage = chain_context3->Input[0]; + count = read_coverage_list (otf, stream, offset, + &chain_context3->LookAhead, -1); + chain_context3->LookaheadGlyphCount = (unsigned) count; + chain_context3->LookupCount + = read_lookup_record_list (otf, stream, + &chain_context3->LookupRecord, -1); + return 0; +} + +static void * +read_gsub_gpos_table (OTF *otf, OTF_TableInfo *table, int gsubp, + enum OTF_ReaderFlag flag) +{ + OTF_Stream *stream = table->stream; + char *errfmt = gsubp ? "GSUB%s" : "GPOS%s"; + void *errret = NULL; + OTF_GSUB_GPOS *gsub_gpos = *table->address; + + if (gsub_gpos) + SEEK_STREAM (stream, 10); + else + { + SEEK_STREAM (stream, 0); + OTF_CALLOC (gsub_gpos, 1, ""); + READ_FIXED (stream, gsub_gpos->Version); + READ_OFFSET (stream, gsub_gpos->ScriptList.offset); + READ_OFFSET (stream, gsub_gpos->FeatureList.offset); + READ_OFFSET (stream, gsub_gpos->LookupList.offset); + *table->address = gsub_gpos; + } + + if (! gsub_gpos->ScriptList.Script + && read_script_list (otf, stream, gsub_gpos->ScriptList.offset, + &gsub_gpos->ScriptList) < 0) + return NULL; + if (flag != OTF_READ_SCRIPTS) + { + if (! gsub_gpos->FeatureList.Feature + && read_feature_list (otf, stream, gsub_gpos->FeatureList.offset, + &gsub_gpos->FeatureList) < 0) + return NULL; + if (flag != OTF_READ_FEATURES) + { + if (! gsub_gpos->LookupList.Lookup + && read_lookup_list (otf, stream, gsub_gpos->LookupList.offset, + &gsub_gpos->LookupList, gsubp) < 0) + return NULL; + } + } + + return gsub_gpos; +} + + +/* (1-9) "GSUB" table */ + +static unsigned +read_sequence (OTF *otf, OTF_Stream *stream, long offset, OTF_Sequence **seq) +{ + char *errfmt = "Sequence%s"; + unsigned errret = 0; + unsigned count; + int i; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*seq, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*seq)[i].offset); + for (i = 0; i < count; i++) + { + SEEK_STREAM (stream, offset + (*seq)[i].offset); + (*seq)[i].GlyphCount = read_glyph_ids (otf, stream, + &(*seq)[i].Substitute, 0, -1); + if (! (*seq)[i].GlyphCount) + return 0; + } + return count; +} + +static int +read_ligature (OTF *otf, OTF_Stream *stream, long offset, + OTF_Ligature **ligature) +{ + char *errfmt = "Ligature%s"; + int errret = -1; + int count; + int i; + + READ_UINT16 (stream, count); + if (! count) + return 0; + OTF_MALLOC (*ligature, count, ""); + for (i = 0; i < count; i++) + READ_OFFSET (stream, (*ligature)[i].offset); for (i = 0; i < count; i++) { - SEEK_STREAM (stream, offset + (*set)[i].offset); - (*set)[i].ChainSubRuleCount - = read_chain_subrule (otf, stream, offset + (*set)[i].offset, - &(*set)[i].ChainSubRule); - if (! (*set)[i].ChainSubRuleCount) - return 0; + SEEK_STREAM (stream, offset + (*ligature)[i].offset); + READ_GLYPHID (stream, (*ligature)[i].LigGlyph); + (*ligature)[i].CompCount + = read_glyph_ids (otf, stream, &(*ligature)[i].Component, -1, -1); + if (! (*ligature)[i].CompCount) + return -1; } return count; } static unsigned -read_chain_subclass_rule (OTF *otf, OTF_Stream *stream, long offset, - OTF_ChainSubClassRule **rule) +read_ligature_set_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_LigatureSet **ligset) { - char *errfmt = "ChainSubClassRule%s"; - unsigned errret = 0; - unsigned count; + char *errfmt = "LigatureSet%s"; + int errret = 0; + int count; int i; READ_UINT16 (stream, count); if (! count) - OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*rule, count, ""); + return errret; + OTF_MALLOC (*ligset, count, ""); for (i = 0; i < count; i++) - READ_OFFSET (stream, (*rule)[i].offset); + READ_OFFSET (stream, (*ligset)[i].offset); for (i = 0; i < count; i++) { - SEEK_STREAM (stream, offset + (*rule)[i].offset); - (*rule)[i].BacktrackGlyphCount - = read_glyph_ids (otf, stream, - (OTF_GlyphID **) &(*rule)[i].Backtrack, 0); - if (! (*rule)[i].BacktrackGlyphCount) - return 0; - (*rule)[i].InputGlyphCount - = read_glyph_ids (otf, stream, (OTF_GlyphID **) &(*rule)[i].Input, -1); - if (! (*rule)[i].InputGlyphCount) - return 0; - (*rule)[i].LookaheadGlyphCount - = read_glyph_ids (otf, stream, (OTF_GlyphID **) &(*rule)[i].LookAhead, 0); - if (! (*rule)[i].LookaheadGlyphCount) - return 0; - (*rule)[i].SubstCount - = read_subst_lookup_record (otf, stream, &(*rule)[i].SubstLookupRecord); - if (! (*rule)[i].SubstCount) - return 0; + int lig_count; + + SEEK_STREAM (stream, offset + (*ligset)[i].offset); + lig_count = read_ligature (otf, stream, offset + (*ligset)[i].offset, + &(*ligset)[i].Ligature); + if (lig_count < 0) + return errret; + (*ligset)[i].LigatureCount = (unsigned) lig_count; } return count; } static unsigned -read_chain_subclass_set (OTF *otf, OTF_Stream *stream, long offset, - OTF_ChainSubClassSet **set) +read_alternate_set_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_AlternateSet **altset) { - char *errfmt = "ChainSubClassSet%s"; - unsigned errret = 0; + char *errfmt = "AlternateSet%s"; + int errret = 0; unsigned count; int i; READ_UINT16 (stream, count); if (! count) OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); - OTF_MALLOC (*set, count, ""); + OTF_MALLOC (*altset, count, ""); for (i = 0; i < count; i++) - READ_OFFSET (stream, (*set)[i].offset); + READ_OFFSET (stream, (*altset)[i].offset); for (i = 0; i < count; i++) { - SEEK_STREAM (stream, offset + (*set)[i].offset); - (*set)[i].ChainSubClassRuleCnt - = read_chain_subclass_rule (otf, stream, offset + (*set)[i].offset, - &(*set)[i].ChainSubClassRule); - if (! (*set)[i].ChainSubClassRuleCnt) - return 0; + int alt_count; + + SEEK_STREAM (stream, offset + (*altset)[i].offset); + alt_count = read_glyph_ids (otf, stream, &(*altset)[i].Alternate, 0, -1); + if (alt_count < 0) + return errret; + (*altset)[i].GlyphCount = (unsigned) alt_count; } return count; } +static int +read_reverse_chain1 (OTF *otf, OTF_Stream *stream, long offset, + OTF_Coverage *coverage, + OTF_GSUB_ReverseChain1 *reverse_chain) +{ + int count; + + if (read_coverage (otf, stream, offset, coverage) < 0) + return -1; + count = read_coverage_list (otf, stream, offset, + &reverse_chain->Backtrack, -1); + if (count < 0) + return -1; + reverse_chain->BacktrackGlyphCount = (unsigned) count; + count = read_coverage_list (otf, stream, offset, + &reverse_chain->LookAhead, -1); + if (count <= 0) + return -1; + reverse_chain->LookaheadGlyphCount = (unsigned) count; + count = read_glyph_ids (otf, stream, &reverse_chain->Substitute, 0, -1); + if (count <= 0) + return -1; + reverse_chain->GlyphCount = count; + return 0; +} -static int +static int read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset, unsigned type, OTF_LookupSubTableGSUB *subtable) { - char *errfmt = "GSUB LookupSubTable%s"; + char errfmt[256]; int errret = -1; - int count; SEEK_STREAM (stream, offset); - READ_UINT16 (stream, subtable->Format); + READ_USHORT (stream, subtable->Format); + sprintf (errfmt, "GSUB Lookup %d-%d%%s", type, subtable->Format); switch (type) { case 1: @@ -1061,7 +2048,7 @@ read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset, return -1; subtable->u.single2.GlyphCount = read_glyph_ids (otf, stream, &subtable->u.single2.Substitute, - 0); + 0, -1); if (! subtable->u.single2.GlyphCount) return -1; } @@ -1080,20 +2067,55 @@ read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset, else OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); break; - + case 3: + if (subtable->Format == 1) + { + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + subtable->u.alternate1.AlternateSetCount + = read_alternate_set_list (otf, stream, offset, + &subtable->u.alternate1.AlternateSet); + if (! subtable->u.alternate1.AlternateSetCount) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); break; case 4: if (subtable->Format == 1) { - read_coverage (otf, stream, offset, &subtable->Coverage); - count = (read_ligature_set - (otf, stream, offset, - &subtable->u.ligature1.LigatureSet)); - if (count < 0) + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) return -1; - subtable->u.ligature1.LigSetCount = (unsigned) count; + subtable->u.ligature1.LigSetCount + = read_ligature_set_list (otf, stream, offset, + &subtable->u.ligature1.LigatureSet); + if (! subtable->u.ligature1.LigSetCount) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 5: + if (subtable->Format == 1) + { + if (read_context1 (otf, stream, offset, &subtable->Coverage, + &subtable->u.context1) < 0) + return errret; + } + else if (subtable->Format == 2) + { + if (read_context2 (otf, stream, offset, &subtable->Coverage, + &subtable->u.context2) < 0) + return errret; + } + else if (subtable->Format == 3) + { + if (read_context3 (otf, stream, offset, &subtable->Coverage, + &subtable->u.context3) < 0) + return errret; } else OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); @@ -1102,66 +2124,72 @@ read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset, case 6: if (subtable->Format == 1) { - read_coverage (otf, stream, offset, &subtable->Coverage); - subtable->u.chain_context1.ChainSubRuleSetCount - = (read_chain_subrule_set - (otf, stream, offset, - &subtable->u.chain_context1.ChainSubRuleSet)); + if (read_chain_context1 (otf, stream, offset, &subtable->Coverage, + &subtable->u.chain_context1) < 0) + return errret; } else if (subtable->Format == 2) { - read_coverage (otf, stream, offset, &subtable->Coverage); - read_class_def (otf, stream, offset, - &subtable->u.chain_context2.Backtrack); - read_class_def (otf, stream, offset, - &subtable->u.chain_context2.Input); - read_class_def (otf, stream, offset, - &subtable->u.chain_context2.LookAhead); - subtable->u.chain_context2.ChainSubClassSetCnt - = (read_chain_subclass_set - (otf, stream, offset, - &subtable->u.chain_context2.ChainSubClassSet)); + if (read_chain_context2 (otf, stream, offset, &subtable->Coverage, + &subtable->u.chain_context2) < 0) + return errret; } else if (subtable->Format == 3) { - count = (read_coverage_list - (otf, stream, offset, - &subtable->u.chain_context3.Backtrack)); - if (count < 0) - return -1; - subtable->u.chain_context3.BacktrackGlyphCount - = (unsigned) count; - count = (read_coverage_list - (otf, stream, offset, - &subtable->u.chain_context3.Input)); - if (count <= 0) - return -1; - subtable->u.chain_context3.InputGlyphCount - = (unsigned) count; - subtable->Coverage = subtable->u.chain_context3.Input[0]; - count = (read_coverage_list - (otf, stream, offset, - &subtable->u.chain_context3.LookAhead)); - subtable->u.chain_context3.LookaheadGlyphCount - = (unsigned) count; - subtable->u.chain_context3.SubstCount - = (read_subst_lookup_record - (otf, stream, - &subtable->u.chain_context3.SubstLookupRecord)); + if (read_chain_context3 (otf, stream, offset, &subtable->Coverage, + &subtable->u.chain_context3) < 0) + return errret; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 7: + if (subtable->Format == 1) + { + unsigned ex_type; + long ex_offset; + OTF_LookupSubTableGSUB *ex_subtable; + + READ_USHORT (stream, ex_type); + READ_ULONG (stream, ex_offset); + OTF_CALLOC (ex_subtable, 1, " (SubTable)"); + if (read_lookup_subtable_gsub (otf, stream, offset + ex_offset, + ex_type, ex_subtable) < 0) + return errret; + subtable->u.extension1.ExtensionLookupType = ex_type; + subtable->u.extension1.ExtensionOffset = ex_offset; + subtable->u.extension1.ExtensionSubtable = ex_subtable; } else OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); break; + case 8: + if (subtable->Format == 1) + { + if (read_reverse_chain1 (otf, stream, offset, &subtable->Coverage, + &subtable->u.reverse_chain1) < 0) + return errret; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; default: - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); } return 0; } +static void * +read_gsub_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) +{ + return read_gsub_gpos_table (otf, table, 1, flag); +} + -/* GPOS */ +/* (1-10) "GPOS" table */ static int read_value_record (OTF *otf, OTF_Stream *stream, long offset, @@ -1171,6 +2199,7 @@ read_value_record (OTF *otf, OTF_Stream *stream, long offset, OTF_StreamState state; int size, i; + memset (value_record, 0, sizeof (OTF_ValueRecord)); if (! bit) return 0; for (i = 0, size = 0; i < 8; i++) @@ -1179,7 +2208,7 @@ read_value_record (OTF *otf, OTF_Stream *stream, long offset, if (bit & OTF_XPlacement) READ_INT16 (stream, value_record->XPlacement); - if (bit & OTF_XPlacement) + if (bit & OTF_YPlacement) READ_INT16 (stream, value_record->YPlacement); if (bit & OTF_XAdvance) READ_INT16 (stream, value_record->XAdvance); @@ -1266,7 +2295,7 @@ read_mark_array (OTF *otf, OTF_Stream *stream, long offset, int errret = -1; OTF_StreamState state; int i; - + READ_OFFSET (stream, array->offset); SAVE_STREAM (stream, state); SEEK_STREAM (stream, offset + array->offset); @@ -1286,35 +2315,66 @@ read_mark_array (OTF *otf, OTF_Stream *stream, long offset, } static int -read_base_array (OTF *otf, OTF_Stream *stream, long offset, - unsigned ClassCount, OTF_BaseArray *array) +read_anchor_array (OTF *otf, OTF_Stream *stream, long offset, + unsigned ClassCount, OTF_AnchorArray *array) { - char *errfmt = "BaseArray%s"; + char *errfmt = "AnchorArray%s"; int errret = -1; OTF_StreamState state; int i, j; - + READ_OFFSET (stream, array->offset); SAVE_STREAM (stream, state); SEEK_STREAM (stream, offset + array->offset); - READ_UINT16 (stream, array->BaseCount); - OTF_MALLOC (array->BaseRecord, array->BaseCount, ""); - for (i = 0; i < array->BaseCount; i++) + READ_UINT16 (stream, array->Count); + OTF_MALLOC (array->AnchorRecord, array->Count, ""); + for (i = 0; i < array->Count; i++) { - OTF_MALLOC (array->BaseRecord[i].BaseAnchor, ClassCount, - " (BaseRecord)"); + OTF_MALLOC (array->AnchorRecord[i].Anchor, ClassCount, + " (AnchorRecord)"); for (j = 0; j < ClassCount; j++) - READ_OFFSET (stream, array->BaseRecord[i].BaseAnchor[j].offset); + READ_OFFSET (stream, array->AnchorRecord[i].Anchor[j].offset); } - for (i = 0; i < array->BaseCount; i++) + for (i = 0; i < array->Count; i++) for (j = 0; j < ClassCount; j++) if (read_anchor (otf, stream, offset + array->offset, - &array->BaseRecord[i].BaseAnchor[j]) < 0) + &array->AnchorRecord[i].Anchor[j]) < 0) return -1; RESTORE_STREAM (stream, state); return 0; } +static OTF_PairSet * +read_pair_set_list (OTF *otf, OTF_Stream *stream, long offset, unsigned num, + enum OTF_ValueFormat bit1, enum OTF_ValueFormat bit2) +{ + char *errfmt = "PairSet%s"; + void *errret = NULL; + OTF_StreamState state; + OTF_PairSet *set; + int i, j; + + OTF_MALLOC (set, num, ""); + for (i = 0; i < num; i++) + READ_OFFSET (stream, set[i].offset); + SAVE_STREAM (stream, state); + for (i = 0; i < num; i++) + { + SEEK_STREAM (stream, offset + set[i].offset); + READ_UINT16 (stream, set[i].PairValueCount); + OTF_MALLOC (set[i].PairValueRecord, set[i].PairValueCount, ""); + for (j = 0; j < set[i].PairValueCount; j++) + { + OTF_PairValueRecord *rec = set[i].PairValueRecord + j; + + READ_UINT16 (stream, rec->SecondGlyph); + read_value_record (otf, stream, offset, bit1, &rec->Value1); + read_value_record (otf, stream, offset, bit2, &rec->Value2); + } + } + RESTORE_STREAM (stream, state); + return set; +} static OTF_Class1Record * read_class1_record_list (OTF *otf, OTF_Stream *stream, long offset, @@ -1342,160 +2402,318 @@ read_class1_record_list (OTF *otf, OTF_Stream *stream, long offset, return rec; } +static unsigned +read_entry_exit_list (OTF *otf, OTF_Stream *stream, long offset, + OTF_EntryExitRecord **rec) +{ + char *errfmt = "EntryExitSet%s"; + int errret = 0; + unsigned count; + int i; + OTF_StreamState state; + + READ_UINT16 (stream, count); + if (! count) + OTF_ERROR (OTF_ERROR_TABLE, " (zero count)"); + OTF_MALLOC (*rec, count, ""); + for (i = 0; i < count; i++) + { + READ_OFFSET (stream, (*rec)[i].EntryAnchor.offset); + READ_OFFSET (stream, (*rec)[i].ExitAnchor.offset); + } + SAVE_STREAM (stream, state); + for (i = 0; i < count; i++) + { + if (read_anchor (otf, stream, offset, &(*rec)[i].EntryAnchor) < 0) + return -1; + if (read_anchor (otf, stream, offset, &(*rec)[i].ExitAnchor) < 0) + return -1; + } + RESTORE_STREAM (stream, state); + return count; +} + +static int +read_ligature_attach (OTF *otf, OTF_Stream *stream, long offset, + unsigned ClassCount, OTF_LigatureAttach *attach) +{ + char *errfmt = "LigatureAttach%s"; + int errret = 1; + int i, j; + + SEEK_STREAM (stream, offset + attach->offset); + READ_UINT16 (stream, attach->ComponentCount); + OTF_MALLOC (attach->ComponentRecord, attach->ComponentCount, ""); + for (i = 0; i < attach->ComponentCount; i++) + { + OTF_MALLOC (attach->ComponentRecord[i].LigatureAnchor, ClassCount, + " (ComponentRecord)"); + for (j = 0; j < ClassCount; j++) + READ_OFFSET (stream, + attach->ComponentRecord[i].LigatureAnchor[j].offset); + } + for (i = 0; i < attach->ComponentCount; i++) + for (j = 0; j < ClassCount; j++) + { + if (attach->ComponentRecord[i].LigatureAnchor[j].offset) + { + if (read_anchor (otf, stream, offset + attach->offset, + &attach->ComponentRecord[i].LigatureAnchor[j]) < 0) + return -1; + } + else + attach->ComponentRecord[i].LigatureAnchor[j].AnchorFormat = 0; + } + return 0; +} + +static int +read_ligature_array (OTF *otf, OTF_Stream *stream, long offset, + unsigned class_count, OTF_LigatureArray *array) +{ + char *errfmt = "LigatureArray%s"; + int errret = -1; + OTF_StreamState state; + int i; + + READ_OFFSET (stream, array->offset); + SAVE_STREAM (stream, state); + SEEK_STREAM (stream, offset + array->offset); + READ_UINT16 (stream, array->LigatureCount); + OTF_MALLOC (array->LigatureAttach, array->LigatureCount, ""); + for (i = 0; i < array->LigatureCount; i++) + READ_OFFSET (stream, array->LigatureAttach[i].offset); + for (i = 0; i < array->LigatureCount; i++) + read_ligature_attach (otf, stream, offset + array->offset, + class_count, array->LigatureAttach + i); + RESTORE_STREAM (stream, state); + return 0; +} -static int +static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream, long offset, unsigned type, OTF_LookupSubTableGPOS *subtable) { - char *errfmt = "GPOS LookupSubTable%s"; + char errfmt[256]; int errret = -1; SEEK_STREAM (stream, offset); READ_UINT16 (stream, subtable->Format); + sprintf (errfmt, "GPOS Lookup %d-%d%%s", type, subtable->Format); switch (type) { case 1: -#if 0 if (subtable->Format == 1) { - read_coverage (otf, stream, offset, &subtable->Coverage); - subtable->u.single1.DeltaGlyphID = READ_INT16 (stream); + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + READ_UINT16 (stream, subtable->u.single1.ValueFormat); + read_value_record (otf, stream, offset, + subtable->u.single1.ValueFormat, + &subtable->u.single1.Value); + } + else if (subtable->Format == 2) + { + OTF_GPOS_Single2 *single2 = &subtable->u.single2; + int i; + + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + READ_UINT16 (stream, single2->ValueFormat); + READ_UINT16 (stream, single2->ValueCount); + OTF_CALLOC (single2->Value, single2->ValueCount," (ValueRecord)"); + for (i = 0; i < single2->ValueCount; i++) + read_value_record (otf, stream, offset, single2->ValueFormat, + single2->Value + i); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 2: + if (subtable->Format == 1) + { + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + READ_UINT16 (stream, subtable->u.pair1.ValueFormat1); + READ_UINT16 (stream, subtable->u.pair1.ValueFormat2); + READ_UINT16 (stream, subtable->u.pair1.PairSetCount); + subtable->u.pair1.PairSet + = read_pair_set_list (otf, stream, offset, + subtable->u.pair1.PairSetCount, + subtable->u.pair1.ValueFormat1, + subtable->u.pair1.ValueFormat2); + if (! subtable->u.pair1.PairSet) + return -1; } else if (subtable->Format == 2) { + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + READ_UINT16 (stream, subtable->u.pair2.ValueFormat1); + READ_UINT16 (stream, subtable->u.pair2.ValueFormat2); + if (read_class_def (otf, stream, offset, + &subtable->u.pair2.ClassDef1) < 0 + || read_class_def (otf, stream, offset, + &subtable->u.pair2.ClassDef2) < 0) + return -1; + READ_UINT16 (stream, subtable->u.pair2.Class1Count); + READ_UINT16 (stream, subtable->u.pair2.Class2Count); + subtable->u.pair2.Class1Record + = read_class1_record_list (otf, stream, offset, + subtable->u.pair2.Class1Count, + subtable->u.pair2.ValueFormat1, + subtable->u.pair2.Class2Count, + subtable->u.pair2.ValueFormat2); + if (! subtable->u.pair2.Class1Record) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 3: + if (subtable->Format == 1) + { + if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0) + return -1; + subtable->u.cursive1.EntryExitCount + = read_entry_exit_list (otf, stream, offset, + &subtable->u.cursive1.EntryExitRecord); + if (! subtable->u.cursive1.EntryExitCount) + return -1; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 4: + if (subtable->Format == 1) + { read_coverage (otf, stream, offset, &subtable->Coverage); - subtable->u.single2.GlyphCount - = read_glyph_ids (otf, stream, - &subtable->u.single2.Substitute, 0); + read_coverage (otf, stream, offset, + &subtable->u.mark_base1.BaseCoverage); + READ_UINT16 (stream, subtable->u.mark_base1.ClassCount); + read_mark_array (otf, stream, offset, + &subtable->u.mark_base1.MarkArray); + read_anchor_array (otf, stream, offset, + subtable->u.mark_base1.ClassCount, + &subtable->u.mark_base1.BaseArray); + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 5: + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + read_coverage (otf, stream, offset, + &subtable->u.mark_lig1.LigatureCoverage); + READ_UINT16 (stream, subtable->u.mark_lig1.ClassCount); + read_mark_array (otf, stream, offset, + &subtable->u.mark_lig1.MarkArray); + read_ligature_array (otf, stream, offset, + subtable->u.mark_lig1.ClassCount, + &subtable->u.mark_lig1.LigatureArray); + } + break; + + case 6: + if (subtable->Format == 1) + { + read_coverage (otf, stream, offset, &subtable->Coverage); + read_coverage (otf, stream, offset, + &subtable->u.mark_mark1.Mark2Coverage); + READ_UINT16 (stream, subtable->u.mark_base1.ClassCount); + read_mark_array (otf, stream, offset, + &subtable->u.mark_mark1.Mark1Array); + read_anchor_array (otf, stream, offset, + subtable->u.mark_mark1.ClassCount, + &subtable->u.mark_mark1.Mark2Array); } else OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); -#endif break; - case 2: + case 7: if (subtable->Format == 1) { - read_coverage (otf, stream, offset, &subtable->Coverage); + if (read_context1 (otf, stream, offset, &subtable->Coverage, + &subtable->u.context1) < 0) + return errret; } else if (subtable->Format == 2) { - SEEK_STREAM (stream, offset + 2); - read_coverage (otf, stream, offset, &subtable->Coverage); - READ_UINT16 (stream, subtable->u.pair2.ValueFormat1); - READ_UINT16 (stream, subtable->u.pair2.ValueFormat2); - read_class_def (otf, stream, offset, - &subtable->u.pair2.ClassDef1); - read_class_def (otf, stream, offset, - &subtable->u.pair2.ClassDef2); - READ_UINT16 (stream, subtable->u.pair2.Class1Count); - READ_UINT16 (stream, subtable->u.pair2.Class2Count); - subtable->u.pair2.Class1Record - = read_class1_record_list (otf, stream, offset, - subtable->u.pair2.Class1Count, - subtable->u.pair2.ValueFormat1, - subtable->u.pair2.Class2Count, - subtable->u.pair2.ValueFormat2); + if (read_context2 (otf, stream, offset, &subtable->Coverage, + &subtable->u.context2) < 0) + return errret; } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); - break; - - case 4: - if (subtable->Format == 1) + else if (subtable->Format == 3) { - read_coverage (otf, stream, offset, &subtable->Coverage); - read_coverage (otf, stream, offset, - &subtable->u.mark_base1.BaseCoverage); - READ_UINT16 (stream, subtable->u.mark_base1.ClassCount); - read_mark_array (otf, stream, offset, - &subtable->u.mark_base1.MarkArray); - read_base_array (otf, stream, offset, - subtable->u.mark_base1.ClassCount, - &subtable->u.mark_base1.BaseArray); + if (read_context3 (otf, stream, offset, &subtable->Coverage, + &subtable->u.context3) < 0) + return errret; } else OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); break; - case 6: -#if 0 + case 8: if (subtable->Format == 1) { - read_coverage (otf, stream, offset, - &subtable->u.chain_context1.Coverage); - subtable->u.chain_context1.ChainSubRuleSetCount - = (read_chain_subrule_set - (otf, stream, offset, - &subtable->u.chain_context1.ChainSubRuleSet)); + if (read_chain_context1 (otf, stream, offset, &subtable->Coverage, + &subtable->u.chain_context1) < 0) + return errret; } else if (subtable->Format == 2) { - read_coverage (otf, stream, offset, - &subtable->u.chain_context2.Coverage); - read_class_def (otf, stream, offset, - &subtable->u.chain_context2.Backtrack); - read_class_def (otf, stream, offset, - &subtable->u.chain_context2.Input); - read_class_def (otf, stream, offset, - &subtable->u.chain_context2.LookAhead); - subtable->u.chain_context2.ChainSubClassSetCnt - = (read_chain_subclass_set - (otf, stream, offset, - &subtable->u.chain_context2.ChainSubClassSet)); + if (read_chain_context2 (otf, stream, offset, &subtable->Coverage, + &subtable->u.chain_context2) < 0) + return errret; } else if (subtable->Format == 3) { - subtable->u.chain_context3.BacktrackGlyphCount - = (read_coverage_list - (otf, stream, offset, - &subtable->u.chain_context3.Backtrack)); - subtable->u.chain_context3.InputGlyphCount - = (read_coverage_list - (otf, stream, offset, - &subtable->u.chain_context3.Input)); - subtable->u.chain_context3.LookaheadGlyphCount - = (read_coverage_list - (otf, stream, offset, - &subtable->u.chain_context3.LookAhead)); - subtable->u.chain_context3.SubstCount - = (read_subst_lookup_record - (otf, stream, - &subtable->u.chain_context3.SubstLookupRecord)); + if (read_chain_context3 (otf, stream, offset, &subtable->Coverage, + &subtable->u.chain_context3) < 0) + return errret; + } + else + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); + break; + + case 9: + if (subtable->Format == 1) + { + unsigned ex_type; + long ex_offset; + OTF_LookupSubTableGPOS *ex_subtable; + + READ_USHORT (stream, ex_type); + READ_ULONG (stream, ex_offset); + OTF_CALLOC (ex_subtable, 1, " (SubTable)"); + if (read_lookup_subtable_gpos (otf, stream, offset + ex_offset, + ex_type, ex_subtable) < 0) + return errret; + subtable->u.extension1.ExtensionLookupType = ex_type; + subtable->u.extension1.ExtensionOffset = ex_offset; + subtable->u.extension1.ExtensionSubtable = ex_subtable; } else OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)"); -#endif + break; default: - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); + OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)"); } return 0; } - static void * -read_gpos_table (OTF *otf, OTF_Stream *stream) +read_gpos_table (OTF *otf, OTF_TableInfo *table, enum OTF_ReaderFlag flag) { - char *errfmt = "GPOS%s"; - void *errret = NULL; - OTF_GPOS *gpos; - - OTF_CALLOC (gpos, 1, ""); - READ_FIXED (stream, gpos->Version); - READ_OFFSET (stream, gpos->ScriptList.offset); - READ_OFFSET (stream, gpos->FeatureList.offset); - READ_OFFSET (stream, gpos->LookupList.offset); - - if (read_script_list (otf, stream, gpos->ScriptList.offset, - &gpos->ScriptList) < 0 - || read_feature_list (otf, stream, gpos->FeatureList.offset, - &gpos->FeatureList) < 0 - || read_lookup_list (otf, stream, gpos->LookupList.offset, - &gpos->LookupList, 0) < 0) - return NULL; - return gpos; + return read_gsub_gpos_table (otf, table, 0, flag); } @@ -1524,376 +2742,230 @@ read_jstf_table (OTF_Stream *stream, long offset) return jstf; } -#endif +#endif /* 0 */ -/* GDEF */ -static int -read_attach_list (OTF *otf, OTF_Stream *stream, long offset, - OTF_AttachList *list) -{ - char *errfmt = "AttachList%s"; - int errret = -1; - int i, j; - - if (read_coverage (otf, stream, offset, &list->Coverage) < 0) - return -1; - READ_UINT16 (stream, list->GlyphCount); - OTF_MALLOC (list->AttachPoint, list->GlyphCount, ""); - for (i = 0; i < list->GlyphCount; i++) - READ_OFFSET (stream, list->AttachPoint[i].offset); - for (i = 0; i < list->GlyphCount; i++) - { - int count; - - SEEK_STREAM (stream, offset + list->AttachPoint[i].offset); - READ_UINT16 (stream, count); - list->AttachPoint[i].PointCount = count; - OTF_MALLOC (list->AttachPoint[i].PointIndex, count, " (PointIndex)"); - for (j = 0; j < count; j++) - READ_UINT16 (stream, list->AttachPoint[i].PointIndex[j]); - } - return 0; -} - -static int -read_caret_value (OTF *otf, OTF_Stream *stream, long offset, - OTF_CaretValue *caret) -{ - char *errfmt = "CaretValue%s"; - int errret = -1; - - SEEK_STREAM (stream, offset + caret->offset); - READ_UINT16 (stream, caret->CaretValueFormat); - if (caret->CaretValueFormat == 1) - READ_INT16 (stream, caret->f.f1.Coordinate); - else if (caret->CaretValueFormat == 2) - READ_UINT16 (stream, caret->f.f2.CaretValuePoint); - else if (caret->CaretValueFormat == 3) - { - READ_INT16 (stream, caret->f.f3.Coordinate); - if (read_device_table (otf, stream, offset + caret->offset, - &caret->f.f3.DeviceTable) < 0) - return -1; - } - else - OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)"); - return 0; -} - -static int -read_lig_caret_list (OTF *otf, OTF_Stream *stream, long offset, - OTF_LigCaretList *list) -{ - char *errfmt = "LigCaretList%s"; - int errret = -1; - int i, j; - - if (read_coverage (otf, stream, offset, &list->Coverage) < 0) - return -1; - READ_UINT16 (stream, list->LigGlyphCount); - OTF_MALLOC (list->LigGlyph, list->LigGlyphCount, ""); - for (i = 0; i < list->LigGlyphCount; i++) - READ_OFFSET (stream, list->LigGlyph[i].offset); - for (i = 0; i < list->LigGlyphCount; i++) - { - int count; - - SEEK_STREAM (stream, offset + list->LigGlyph[i].offset); - READ_UINT16 (stream, count); - list->LigGlyph[i].CaretCount = count; - OTF_MALLOC (list->LigGlyph[i].CaretValue, count, " (CaretValue)"); - for (j = 0; j < count; j++) - READ_OFFSET (stream, list->LigGlyph[i].CaretValue[j].offset); - for (j = 0; j < count; j++) - if (read_caret_value (otf, stream, offset + list->LigGlyph[i].offset, - &list->LigGlyph[i].CaretValue[j]) < 0) - return -1; - } - return 0; -} +/*** (1-11) Structure for OTF */ static int -read_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header) +read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table) { int errret = -1; - READ_FIXED (stream, header->Version); - READ_OFFSET (stream, header->GlyphClassDef); - READ_OFFSET (stream, header->AttachList); - READ_OFFSET (stream, header->LigCaretList); - READ_OFFSET (stream, header->MarkAttachClassDef); + READ_FIXED (stream, table->sfnt_version); + READ_USHORT (stream, table->numTables); + READ_USHORT (stream, table->searchRange); + READ_USHORT (stream, table->enterSelector); + READ_USHORT (stream, table->rangeShift); return 0; } -static void * -read_gdef_table (OTF *otf, OTF_Stream *stream) -{ - char *errfmt = "GDEF%s"; - void *errret = NULL; - OTF_GDEF *gdef; - - OTF_CALLOC (gdef, 1, ""); - read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header); - if (gdef->header.GlyphClassDef) - { - gdef->glyph_class_def.offset = gdef->header.GlyphClassDef; - read_class_def_without_offset (otf, stream, &gdef->glyph_class_def); - } - if (gdef->header.AttachList) - read_attach_list (otf, stream, gdef->header.AttachList, - &gdef->attach_list); - if (gdef->header.LigCaretList) - read_lig_caret_list (otf, stream, gdef->header.LigCaretList, - &gdef->lig_caret_list); - if (gdef->header.MarkAttachClassDef) - { - gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef; - read_class_def_without_offset (otf, stream, &gdef->mark_attach_class_def); - } - - return gdef; -} - - - -/* cmap */ - -static void * -read_cmap_table (OTF *otf, OTF_Stream *stream) +static OTF_Tag +read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table) { - char *errfmt = "cmap%s"; - void *errret = NULL; - OTF_cmap *cmap; - int i; - - OTF_CALLOC (cmap, 1, ""); - READ_USHORT (stream, cmap->version); - READ_USHORT (stream, cmap->numTables); - OTF_MALLOC (cmap->EncodingRecord, cmap->numTables, ""); - for (i = 0; i < cmap->numTables; i++) - { - READ_USHORT (stream, cmap->EncodingRecord[i].platformID); - READ_USHORT (stream, cmap->EncodingRecord[i].encodingID); - READ_ULONG (stream, cmap->EncodingRecord[i].offset); - if (cmap->EncodingRecord[i].platformID == 3 - && cmap->EncodingRecord[i].encodingID == 1) - cmap->Unicode = cmap->EncodingRecord + i; - } - for (i = 0; i < cmap->numTables; i++) - { - unsigned format; - - SEEK_STREAM (stream, cmap->EncodingRecord[i].offset); - READ_USHORT (stream, format); - cmap->EncodingRecord[i].subtable.format = format; - READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length); - if (format == 8 || format == 10 || format == 12) - { - READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length); - READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language); - } - else - { - READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language); - } - switch (format) - { - case 0: - { - OTF_MALLOC (cmap->EncodingRecord[i].subtable.f.f0, 1, - " (EncodingRecord)"); - READ_BYTES (stream, - cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray, - 256); - } - break; - - case 2: - break; - - case 4: - { - OTF_EncodingSubtable4 *sub4; - int segCount; - int j; - unsigned dummy; + int errret = 0; + OTF_Tag tag; - OTF_MALLOC (sub4, 1, " (EncodingSubtable4)"); - cmap->EncodingRecord[i].subtable.f.f4 = sub4; - READ_USHORT (stream, sub4->segCountX2); - segCount = sub4->segCountX2 / 2; - READ_USHORT (stream, sub4->searchRange); - READ_USHORT (stream, sub4->entrySelector); - READ_USHORT (stream, sub4->rangeShift); - OTF_MALLOC (sub4->segments, segCount, " (segCount)"); - for (j = 0; j < segCount; j++) - READ_USHORT (stream, sub4->segments[j].endCount); - READ_USHORT (stream, dummy); - for (j = 0; j < segCount; j++) - READ_USHORT (stream, sub4->segments[j].startCount); - for (j = 0; j < segCount; j++) - READ_SHORT (stream, sub4->segments[j].idDelta); - for (j = 0; j < segCount; j++) - { - unsigned off; - unsigned rest = 2 * (segCount - j); - - READ_USHORT (stream, off); - if (off == 0) - sub4->segments[j].idRangeOffset = 0xFFFF; - else - sub4->segments[j].idRangeOffset = (off - rest) / 2; - } - j = (cmap->EncodingRecord[i].subtable.length - - (14 + 2 * (segCount * 4 + 1))); - sub4->GlyphCount = j / 2; - OTF_MALLOC (sub4->glyphIdArray, sub4->GlyphCount, " (GlyphCount)"); - for (j = 0; j < sub4->GlyphCount; j++) - READ_USHORT (stream, sub4->glyphIdArray[j]); - } - } - } - return cmap; + READ_TAG (stream, tag); + table->tag = tag; + table->name[0] = tag >> 24; + table->name[1] = (tag >> 16) & 0xFF; + table->name[2] = (tag >> 8) & 0xFF; + table->name[3] = tag & 0xFF; + table->name[4] = '\0'; + READ_ULONG (stream, table->checkSum); + READ_ULONG (stream, table->offset); + READ_ULONG (stream, table->length); + return tag; } - - -/* TABLE: name */ - -static char * -read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec, int bytes) +static int +read_header_part (OTF *otf, FILE *fp, FT_Face face) { - char *errfmt = "nameID (%d)"; - void *errret = NULL; - OTF_StreamState state; - char *str; + char *errfmt = "otf header%s"; + int errret = -1; int i; - int c; + OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; - SAVE_STREAM (stream, state); - SEEK_STREAM (stream, stream->pos + rec->offset); + internal_data->table_info[OTF_TABLE_TYPE_HEAD].address = (void *) &otf->head; + internal_data->table_info[OTF_TABLE_TYPE_HEAD].reader = read_head_table; + internal_data->table_info[OTF_TABLE_TYPE_NAME].address = (void *) &otf->name; + internal_data->table_info[OTF_TABLE_TYPE_NAME].reader = read_name_table; + internal_data->table_info[OTF_TABLE_TYPE_CMAP].address = (void *) &otf->cmap; + internal_data->table_info[OTF_TABLE_TYPE_CMAP].reader = read_cmap_table; + internal_data->table_info[OTF_TABLE_TYPE_GDEF].address = (void *) &otf->gdef; + internal_data->table_info[OTF_TABLE_TYPE_GDEF].reader = read_gdef_table; + internal_data->table_info[OTF_TABLE_TYPE_GSUB].address = (void *) &otf->gsub; + internal_data->table_info[OTF_TABLE_TYPE_GSUB].reader = read_gsub_table; + internal_data->table_info[OTF_TABLE_TYPE_GPOS].address = (void *) &otf->gpos; + internal_data->table_info[OTF_TABLE_TYPE_GPOS].reader = read_gpos_table; - if (bytes == 1) + if (fp) { - OTF_MALLOC (str, rec->length + 1, (void *) rec->nameID); - READ_BYTES (stream, str, rec->length); - for (i = 0; i < rec->length; i++) - if (str[i] < 0) - str[i] = '?'; - } - else if (bytes == 2) - { - OTF_MALLOC (str, rec->length / 2 + 1, (void *) rec->nameID); - for (i = 0; i < rec->length / 2; i++) - { - READ_USHORT (stream, c); - if (c >= 128) - c = '?'; - str[i] = c; - } - } - else if (bytes == 4) - { - OTF_MALLOC (str, rec->length / 4 + 1, (void *) rec->nameID); - for (i = 0; i < rec->length / 4; i++) + OTF_Tag head_tag = OTF_tag ("head"); + OTF_Tag name_tag = OTF_tag ("name"); + OTF_Tag cmap_tag = OTF_tag ("cmap"); + OTF_Tag gdef_tag = OTF_tag ("GDEF"); + OTF_Tag gsub_tag = OTF_tag ("GSUB"); + OTF_Tag gpos_tag = OTF_tag ("GPOS"); + OTF_Stream *stream = make_stream ("Offset Table"); + unsigned char ttctag[4]; + + if (! stream) + return -1; + internal_data->header_stream = stream; + + /* Size of Offset Table is 12 bytes. Size of TTC header + (including only the an offset of the first font) is 16. */ + if (setup_stream (stream, fp, 0, 16) < 0) + return -1; + READ_BYTES (stream, ttctag, 4); + if (memcmp (ttctag, "ttcf", 4) == 0) { - READ_ULONG (stream, c); - if (c >= 128) - c = '?'; - str[i] = c; + /* This is a TrueType Collection file. We extract the first font. */ + unsigned version, numfonts, offset; + READ_ULONG (stream, version); + READ_ULONG (stream, numfonts); + READ_ULONG (stream, offset); /* Offset of the first font. */ + if (setup_stream (stream, fp, offset, 12) < 0) + return -1; } - } - str[i] = '\0'; - RESTORE_STREAM (stream, state); - return str; -} + else + SEEK_STREAM (stream, 0L); + if (read_offset_table (otf, stream, &otf->offset_table) < 0) + return -1; + /* Size of each Table Directory is 16 bytes. */ + if (setup_stream (stream, fp, stream->pos, + 16 * otf->offset_table.numTables) < 0) + return -1; -static void * -read_name_table (OTF *otf, OTF_Stream *stream) -{ - char *errfmt = "name%s"; - void *errret = NULL; - OTF_name *name; - int i; + OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables, + " (OffsetTable)"); + for (i = 0; i < otf->offset_table.numTables; i++) + { + OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i); + OTF_TableInfo *table_info = NULL; - OTF_CALLOC (name, 1, ""); - READ_USHORT (stream, name->format); - READ_USHORT (stream, name->count); - READ_USHORT (stream, name->stringOffset); - OTF_MALLOC (name->nameRecord, name->count, ""); - for (i = 0; i < name->count; i++) - { - OTF_NameRecord *rec = name->nameRecord + i; + if (! tag) + return -1; + if (tag == head_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD; + else if (tag == name_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME; + else if (tag == cmap_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP; + else if (tag == gdef_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF; + else if (tag == gsub_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB; + else if (tag == gpos_tag) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS; + + if (table_info) + { + table_info->stream = make_stream (otf->table_dirs[i].name); + if (setup_stream (table_info->stream, fp, + otf->table_dirs[i].offset, + otf->table_dirs[i].length) < 0) + return -1; + } + } - READ_USHORT (stream, rec->platformID); - READ_USHORT (stream, rec->encodingID); - READ_USHORT (stream, rec->languageID); - READ_USHORT (stream, rec->nameID); - READ_USHORT (stream, rec->length); - READ_USHORT (stream, rec->offset); + internal_data->header_stream = NULL; + free_stream (stream); } - for (i = 0; i < name->count; i++) + else { - OTF_NameRecord *rec = name->nameRecord + i; - int nameID = rec->nameID; + OTF_Stream *stream; - if (nameID <= OTF_max_nameID - && ! name->name[nameID]) - { - if (rec->platformID == 0) - name->name[nameID] = read_name (otf, stream, rec, - rec->encodingID <= 3 ? 2 : 4); - else if (rec->platformID == 1 - && rec->encodingID == 0) - name->name[nameID] = read_name (otf, stream, rec, 1); - else if (rec->platformID == 3 - && (rec->encodingID == 1 || rec->encodingID == 10)) - name->name[nameID] = read_name (otf, stream, - rec, rec->encodingID == 1 ? 2 : 4); - } + internal_data->header_stream = NULL; + if ((stream = make_stream_from_ft_face (face, "head"))) + internal_data->table_info[OTF_TABLE_TYPE_HEAD].stream = stream; + if ((stream = make_stream_from_ft_face (face, "name"))) + internal_data->table_info[OTF_TABLE_TYPE_NAME].stream = stream; + if ((stream = make_stream_from_ft_face (face, "cmap"))) + internal_data->table_info[OTF_TABLE_TYPE_CMAP].stream = stream; + if ((stream = make_stream_from_ft_face (face, "GDEF"))) + internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream = stream; + if ((stream = make_stream_from_ft_face (face, "GSUB"))) + internal_data->table_info[OTF_TABLE_TYPE_GSUB].stream = stream; + if ((stream = make_stream_from_ft_face (face, "GPOS"))) + internal_data->table_info[OTF_TABLE_TYPE_GPOS].stream = stream; } - return name; + if (! internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream) + /* We can simulate the GDEF table. */ + internal_data->table_info[OTF_TABLE_TYPE_GDEF].stream + = make_stream ("GDEF"); + return 0; } - +static OTF_TableInfo * +get_table_info (OTF *otf, const char *name) +{ + char *errfmt = "OTF Table Read%s"; + OTF_TableInfo *errret = NULL; + OTF_InternalData *internal_data = otf->internal_data; + OTF_TableInfo *table_info; + OTF_Tag tag = OTF_tag (name); -/* APIs */ + if (! tag) + OTF_ERROR (OTF_ERROR_TABLE, " (invalid table name)"); -OTF_Tag -otf_tag (char *name) -{ - unsigned char *p = (unsigned char *) name; + if (tag == OTF_tag ("head")) + table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD; + else if (tag == OTF_tag ("name")) + table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME; + else if (tag == OTF_tag ("cmap")) + table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP; + else if (tag == OTF_tag ("GDEF")) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF; + else if (tag == OTF_tag ("GSUB")) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB; + else if (tag == OTF_tag ("GPOS")) + table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS; + else + OTF_ERROR (OTF_ERROR_TABLE, " (unsupported table name)"); - if (! name) - return (OTF_Tag) 0; - return (OTF_Tag) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); + if (*table_info->address) + /* Already read. */ + return table_info; + if (! table_info->stream) + OTF_ERROR (OTF_ERROR_TABLE, " (table not found)"); + if (! table_info->reader) + OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)"); + return table_info; } -void -otf_tag_name (OTF_Tag tag, char *name) -{ - name[0] = (char) (tag >> 24); - name[1] = (char) ((tag >> 16) & 0xFF); - name[2] = (char) ((tag >> 8) & 0xFF); - name[3] = (char) (tag & 0xFF); - name[4] = '\0'; -} + +/*** (2) API for reading OTF */ + +/*** (2-1) OTF_open() */ -/* We can't use memory allocation macros in the following functions - because those macros returns from the functions before freeing - memory previously allocated. */ +/* Note: We can't use memory allocation macros in the following + functions because those macros return from the functions before + freeing memory previously allocated. */ OTF * -otf_open (char *otf_name) +OTF_open (const char *otf_name) { FILE *fp; char *errfmt = "opening otf (%s)"; void *errret = NULL; OTF *otf; OTF_InternalData *internal_data; + int len = strlen (otf_name); + const char *ext = otf_name + (len - 4); + if (debug_flag < 0) + set_debug_flag (); + + if (len < 4 + || ext[0] != '.' + || (strncasecmp (ext + 1, "otf", 3) + && strncasecmp (ext + 1, "ttf", 3) + && strncasecmp (ext + 1, "ttc", 3))) + OTF_ERROR (OTF_ERROR_FILE, otf_name); fp = fopen (otf_name, "r"); if (! fp) OTF_ERROR (OTF_ERROR_FILE, otf_name); @@ -1903,7 +2975,7 @@ otf_open (char *otf_name) otf->filename = strdup (otf_name); if (! otf->filename) { - otf_close (otf); + OTF_close (otf); fclose (fp); OTF_ERROR (OTF_ERROR_MEMORY, "filename allocation"); } @@ -1919,9 +2991,9 @@ otf_open (char *otf_name) otf->internal_data->memory_record except for what allocated by the functions allocate_memory_record and make_stream. */ - if (read_header_part (otf, fp) < 0) + if (read_header_part (otf, fp, NULL) < 0) { - otf_close (otf); + OTF_close (otf); fclose (fp); return NULL; } @@ -1930,9 +3002,44 @@ otf_open (char *otf_name) return otf; } +OTF * +OTF_open_ft_face (FT_Face face) +{ + char *errfmt = "opening otf from Freetype (%s)"; + void *errret = NULL; + OTF *otf; + OTF_InternalData *internal_data; + + if (debug_flag < 0) + set_debug_flag (); + + if (! FT_IS_SFNT (face)) + OTF_ERROR (OTF_ERROR_FILE, (char *) face->family_name); + otf = calloc (1, sizeof (OTF)); + if (! otf) + OTF_ERROR (OTF_ERROR_MEMORY, "body allocation"); + otf->filename = NULL; + + internal_data = calloc (1, sizeof (OTF_InternalData)); + if (! internal_data) + OTF_ERROR (OTF_ERROR_MEMORY, " (InternalData"); + otf->internal_data = internal_data; + if (! allocate_memory_record (otf)) + OTF_ERROR (OTF_ERROR_MEMORY, " (InternalData)"); + + if (read_header_part (otf, NULL, face) < 0) + { + OTF_close (otf); + return NULL; + } + + return otf; +} + +/*** (2-2) OTF_close() */ void -otf_close (OTF *otf) +OTF_close (OTF *otf) { OTF_InternalData *internal_data = otf->internal_data; int i; @@ -1940,6 +3047,7 @@ otf_close (OTF *otf) if (internal_data) { OTF_MemoryRecord *memrec = internal_data->memory_record; + OTF_ApplicationData *app_data = internal_data->app_data; if (internal_data->header_stream) free_stream (internal_data->header_stream); @@ -1948,6 +3056,10 @@ otf_close (OTF *otf) if (internal_data->table_info[i].stream) free_stream (internal_data->table_info[i].stream); + for (; app_data; app_data = app_data->next) + if (app_data->data && app_data->freer) + app_data->freer (app_data->data); + while (memrec) { OTF_MemoryRecord *next = memrec->next; @@ -1957,54 +3069,240 @@ otf_close (OTF *otf) free (memrec); memrec = next; } + free (internal_data); } + if (otf->filename) + free (otf->filename); free (otf); } +/*** (2-3) OTF_get_table() */ int -otf_get_table (OTF *otf, char *name) +OTF_get_table (OTF *otf, const char *name) { - char *errfmt = "OTF Table Read"; - int errret = -1; - OTF_InternalData *internal_data = otf->internal_data; - OTF_TableInfo *table_info; - OTF_Tag tag = otf_tag (name); + OTF_TableInfo *table_info = get_table_info (otf, name); + void *address; - if (! tag) - OTF_ERROR (OTF_ERROR_TABLE, " (unknown)"); + if (! table_info) + return -1; + if (! table_info->stream) + /* Already fully loaded. */ + return 0; - if (tag == otf_tag ("head")) - table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD; - else if (tag == otf_tag ("name")) - table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME; - else if (tag == otf_tag ("cmap")) - table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP; - else if (tag == otf_tag ("GDEF")) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF; - else if (tag == otf_tag ("GSUB")) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB; - else if (tag == otf_tag ("GPOS")) - table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS; - else - OTF_ERROR (OTF_ERROR_TABLE, " (unsupported)"); + address = (*table_info->reader) (otf, table_info, OTF_READ_FULL); + free_stream (table_info->stream); + table_info->stream = NULL; + if (! address) + { + table_info->reader = NULL; + return -1; + } + return 0; +} - if (*table_info->address) - return 0; +/*** (2-4) OTF_check_table() */ + +int +OTF_check_table (OTF *otf, const char *name) +{ + return (get_table_info (otf, name) ? 0 : -1); +} + +/*** (2-5) OTF_get_scripts() */ + +int +OTF_get_scripts (OTF *otf, int gsubp) +{ + OTF_TableInfo *table_info + = (otf->internal_data->table_info + + (gsubp ? OTF_TABLE_TYPE_GSUB : OTF_TABLE_TYPE_GPOS)); + void *address; + + if (! table_info->reader) + return -1; if (! table_info->stream) - OTF_ERROR (OTF_ERROR_TABLE, " (not found)"); + /* Already fully loaded. */ + return 0; + + address = (*table_info->reader) (otf, table_info, OTF_READ_SCRIPTS); + if (! address) + { + table_info->reader = NULL; + return -1; + } + return 0; +} + +/*** (2-6) OTF_get_features() */ + +int +OTF_get_features (OTF *otf, int gsubp) +{ + OTF_TableInfo *table_info + = (otf->internal_data->table_info + + (gsubp ? OTF_TABLE_TYPE_GSUB : OTF_TABLE_TYPE_GPOS)); + void *address; + if (! table_info->reader) - OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)"); + return -1; + if (! table_info->stream) + { + if (*table_info->address) + /* Already fully loaded. */ + return 0; + return -1; + } - *table_info->address = (*table_info->reader) (otf, table_info->stream); - free_stream (table_info->stream); - table_info->stream = NULL; - if (! *table_info->address) + address = (*table_info->reader) (otf, table_info, OTF_READ_FEATURES); + if (! address) { table_info->reader = NULL; - OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)"); + return -1; + } + return 0; +} + +/*** (2-7) OTF_check_features */ + +int +OTF_check_features (OTF *otf, int gsubp, + OTF_Tag script, OTF_Tag language, const OTF_Tag *features, + int n_features) +{ + OTF_ScriptList *script_list; + OTF_Script *Script = NULL; + OTF_LangSys *LangSys = NULL; + OTF_FeatureList *feature_list; + int i, j; + + if (OTF_get_features (otf, gsubp) < 0) + { + for (i = 0; i < n_features; i++) + { + OTF_Tag feature = features[i]; + + if (feature == 0) + continue; + if ((((unsigned) feature) & 0x80000000) == 0) + return -1; + } + return 1; + } + if (gsubp) + { + script_list = &otf->gsub->ScriptList; + feature_list = &otf->gsub->FeatureList; + } + else + { + script_list = &otf->gpos->ScriptList; + feature_list = &otf->gpos->FeatureList; + } + for (i = 0; i < script_list->ScriptCount && ! Script; i++) + if (script_list->Script[i].ScriptTag == script) + Script = script_list->Script + i; + if (! Script) + return 0; + if (language) + { + for (i = 0; i < Script->LangSysCount && ! LangSys; i++) + if (Script->LangSysRecord[i].LangSysTag == language) + LangSys = Script->LangSys + i; + } + if (! LangSys) + LangSys = &Script->DefaultLangSys; + for (j = 0; j < n_features; j++) + { + OTF_Tag feature = features[j]; + int negate = 0; + + if (feature == 0) + continue; + if (((unsigned) feature) & 0x80000000) + { + feature = (OTF_Tag) (((unsigned) feature) & 0x7FFFFFFF); + negate = 1; + } + for (i = 0; i < LangSys->FeatureCount; i++) + if (feature_list->Feature[LangSys->FeatureIndex[i]].FeatureTag + == feature) + { + if (negate) + return 0; + break; + } + if (i == LangSys->FeatureCount) + return 0; } + return 1; +} + +/*** (5) API miscellaneous ***/ + +OTF_Tag +OTF_tag (const char *name) +{ + const unsigned char *p = (unsigned char *) name; + + if (! name) + return (OTF_Tag) 0; + return (OTF_Tag) ((p[0] << 24) + | (! p[1] ? 0 + : ((p[1] << 16) + | (! p[2] ? 0 + : (p[2] << 8) | p[3])))); +} + +void +OTF_tag_name (OTF_Tag tag, char *name) +{ + name[0] = (char) (tag >> 24); + name[1] = (char) ((tag >> 16) & 0xFF); + name[2] = (char) ((tag >> 8) & 0xFF); + name[3] = (char) (tag & 0xFF); + name[4] = '\0'; +} + +int +OTF_put_data (OTF *otf, char *id, void *data, void (*freer) (void *data)) +{ + char *errfmt = "appdata %s"; + int errret = -1; + OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; + OTF_ApplicationData *app_data = internal_data->app_data; + int len = strlen (id) + 1; + + for (; app_data; app_data = app_data->next) + if (memcmp (app_data->id, id, len) == 0) + { + if (app_data->data && app_data->freer) + app_data->freer (app_data->data); + break; + } + if (! app_data) + { + OTF_MALLOC (app_data, sizeof (OTF_ApplicationData), id); + app_data->next = internal_data->app_data; + internal_data->app_data = app_data; + OTF_MALLOC (app_data->id, len, id); + memcpy (app_data->id, id, len); + } + app_data->data = data; + app_data->freer = freer; return 0; } + +void * +OTF_get_data (OTF *otf, char *id) +{ + OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data; + OTF_ApplicationData *app_data = internal_data->app_data; + + for (; app_data; app_data = app_data->next) + if (strcmp (app_data->id, id) == 0) + return app_data->data; + return NULL; +}