+/* otfopen.c -- OpenType font reader.
+
+Copyright (C) 2003, 2004
+ 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <config.h>
#include "otf.h"
-#include "otfutil.h"
-
-/* OTF_Stream
+#include "otferror.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
+*/
+\f
+/* (0) Stream handler
Example of typical usage of OTF_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, "");
return stream;
#define READ_GLYPHID READ_USHORT
\f
+/*** (1) Structures for OTF Layout tables and OTF itself */
+
+/*** (1-1) Basic types and functions */
enum OTF_TableType
{
} \
} while (0)
-
-\f
-
-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;
-}
-
-
\f
+/*** (1-2) "head" table */
static void *
read_head_table (OTF *otf, OTF_Stream *stream)
}
\f
+/*** (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 = "nameID (%d)";
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, "");
+ 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);
- for (i = 0; i < list->ScriptCount; i++)
+ OTF_MALLOC (rec->name, rec->length + 1, (void *) rec->nameID);
+ 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;
+
+ 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_Stream *stream)
{
- char *errfmt = "Feature List%s";
- int errret = -1;
- int i, j;
+ 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;
+ return name;
}
-static int read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream,
- long offset, unsigned type,
- OTF_LookupSubTable *subtable);
-static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
- long offset, unsigned type,
- OTF_LookupSubTable *subtable);
+\f
+/*** (1-4) "cmap" table */
-static int
-read_lookup_list (OTF *otf, OTF_Stream *stream, long offset,
- OTF_LookupList *list, int gsub)
+static void *
+read_cmap_table (OTF *otf, OTF_Stream *stream)
{
- 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, "");
+ char *errfmt = "cmap%s";
+ void *errret = NULL;
+ OTF_cmap *cmap;
+ int unicode_bmp_index = -1, unicode_full_index = -1;
+ int i;
- for (i = 0; i < list->LookupCount; i++)
- READ_OFFSET (stream, list->Lookup[i].offset);
- for (i = 0; i < list->LookupCount; 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++)
{
- OTF_Lookup *lookup = list->Lookup + i;
+ unsigned platformID, encodingID;
- 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)");
- OTF_CALLOC (lookup->SubTable, lookup->SubTableCount,
- " (SubTable)");
- for (j = 0; j < lookup->SubTableCount; j++)
- READ_OFFSET (stream, lookup->SubTableOffset[j]);
- if (gsub)
- for (j = 0; j < lookup->SubTableCount; j++)
+ 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;
+ }
+ }
+ 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:
{
- long this_offset
- = offset + lookup->offset + lookup->SubTableOffset[j];
+ OTF_MALLOC (cmap->EncodingRecord[i].subtable.f.f0, 1,
+ " (EncodingRecord)");
+ READ_BYTES (stream,
+ cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray,
+ 256);
+ }
+ break;
- if (read_lookup_subtable_gsub (otf, stream, this_offset,
- lookup->LookupType,
- lookup->SubTable + j) < 0)
- return errret;
+ case 2:
+ OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+ 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]);
}
- else
- for (j = 0; j < lookup->SubTableCount; j++)
+ break;
+
+ case 6:
{
- long this_offset
- = offset + lookup->offset + lookup->SubTableOffset[j];
+ OTF_EncodingSubtable6 *sub6;
+ int j;
- if (read_lookup_subtable_gpos (otf, stream, this_offset,
- lookup->LookupType,
- lookup->SubTable + j) < 0)
- return errret;
+ 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[i].startCharCode);
+ READ_ULONG (stream, sub12->Groups[i].endCharCode);
+ READ_ULONG (stream, sub12->Groups[i].startGlyphID);
+ }
}
+ 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_cmapSegument *seg = sub4->segments + i;
+ int c;
+
+ if (seg->idRangeOffset == 0xFFFF)
+ for (c = seg->startCount; c <= seg->endCount; c++)
+ {
+ glyph_id = c + seg->idDelta;
+ 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;
+ }
+
+ return cmap;
}
+\f
+/*** (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)
{
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
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, "");
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)");
}
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);
{
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;
}
}
\f
-/* 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;
+ int i, j;
- READ_UINT16 (stream, count);
- if (! count)
- return 0;
- OTF_MALLOC (*ligset, count, "");
- for (i = 0; i < count; i++)
- READ_OFFSET (stream, (*ligset)[i].offset);
- for (i = 0; i < count; i++)
+ 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 lig_count;
+ int 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;
+ 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 count;
+ 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_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;
+}
+
+\f
+/*** (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;
+
+ 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;
}
+\f
+/*** (1-8) Structures common to GSUB and GPOS */
+
static unsigned
-read_subst_lookup_record (OTF *otf, OTF_Stream *stream,
- OTF_SubstLookupRecord **record)
+read_lookup_record_list (OTF *otf, OTF_Stream *stream,
+ OTF_LookupRecord **record, int count)
{
- char *errfmt = "SubstLookupRecord%s";
+ char *errfmt = "LookupRecord%s";
unsigned errret = 0;
- unsigned count;
int i;
- READ_UINT16 (stream, count);
+ if (count < 0)
+ READ_UINT16 (stream, count);
if (! count)
OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
OTF_MALLOC (*record, count, "");
}
static unsigned
-read_chain_subrule (OTF *otf, OTF_Stream *stream, long offset,
- OTF_ChainSubRule **rule)
+read_rule_list (OTF *otf, OTF_Stream *stream, long offset, OTF_Rule **rule)
{
- char *errfmt = "ChainSubRule%s";
+ char *errfmt = "List of Rule%s";
unsigned errret = 0;
+ OTF_StreamState state;
unsigned count;
int i;
OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
OTF_MALLOC (*rule, count, "");
for (i = 0; i < count; i++)
- READ_OFFSET (stream, (*rule)[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++)
{
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;
- (*rule)[i].InputGlyphCount
- = read_glyph_ids (otf, stream, &(*rule)[i].Input, -1);
- if (! (*rule)[i].InputGlyphCount)
- return 0;
- (*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_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;
}
static unsigned
-read_chain_subrule_set (OTF *otf, OTF_Stream *stream, long offset,
- OTF_ChainSubRuleSet **set)
+read_rule_set_list (OTF *otf, OTF_Stream *stream, long offset,
+ OTF_RuleSet **set)
{
- char *errfmt = "ChainSubRuleSet%s";
+ char *errfmt = "List of RuleSet%s";
unsigned errret = 0;
+ OTF_StreamState state;
unsigned count;
int i;
OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
OTF_MALLOC (*set, count, "");
for (i = 0; i < count; i++)
- READ_OFFSET (stream, (*set)[i].offset);
+ {
+ 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].ChainSubRuleCount
- = read_chain_subrule (otf, stream, offset + (*set)[i].offset,
- &(*set)[i].ChainSubRule);
- if (! (*set)[i].ChainSubRuleCount)
- return 0;
+ (*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_chain_subclass_rule (OTF *otf, OTF_Stream *stream, long offset,
- OTF_ChainSubClassRule **rule)
+read_class_rule_list (OTF *otf, OTF_Stream *stream, long offset,
+ OTF_ClassRule **rule)
{
- char *errfmt = "ChainSubClassRule%s";
+ char *errfmt = "ClassRule%s";
unsigned errret = 0;
+ OTF_StreamState state;
unsigned count;
int i;
OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
OTF_MALLOC (*rule, count, "");
for (i = 0; i < count; i++)
- READ_OFFSET (stream, (*rule)[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++)
{
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;
+ 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_subclass_set (OTF *otf, OTF_Stream *stream, long offset,
- OTF_ChainSubClassSet **set)
+read_class_set_list (OTF *otf, OTF_Stream *stream, long offset,
+ OTF_ClassSet **set)
{
- char *errfmt = "ChainSubClassSet%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_MALLOC (*set, 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++)
- {
- 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;
- }
+ 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 int
-read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset,
- unsigned type, OTF_LookupSubTable *subtable)
+static unsigned
+read_chain_rule_list (OTF *otf, OTF_Stream *stream, long offset,
+ OTF_ChainRule **rule)
{
- char *errfmt = "GSUB LookupSubTable%s";
- int errret = -1;
- int count;
-
+ char *errfmt = "ChainRule%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);
+ for (i = 0; i < count; i++)
+ {
+ SEEK_STREAM (stream, offset + (*rule)[i].offset);
+ (*rule)[i].BacktrackGlyphCount
+ = read_glyph_ids (otf, stream, &(*rule)[i].Backtrack, 0, -1);
+ (*rule)[i].InputGlyphCount
+ = read_glyph_ids (otf, stream, &(*rule)[i].Input, -1, -1);
+ if (! (*rule)[i].InputGlyphCount)
+ OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+ (*rule)[i].LookaheadGlyphCount
+ = 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_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 = "ChainClassSet%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++)
+ /* 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_Stream *stream, int gsubp)
+{
+ char *errfmt = gsubp ? "GSUB%s" : "GPOS%s";
+ void *errret = NULL;
+ OTF_GSUB_GPOS *gsub_gpos;
+
+ 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);
+
+ if (read_script_list (otf, stream, gsub_gpos->ScriptList.offset,
+ &gsub_gpos->ScriptList) < 0
+ || read_feature_list (otf, stream, gsub_gpos->FeatureList.offset,
+ &gsub_gpos->FeatureList) < 0
+ || read_lookup_list (otf, stream, gsub_gpos->LookupList.offset,
+ &gsub_gpos->LookupList, gsubp) < 0)
+ return NULL;
+ return gsub_gpos;
+}
+
+\f
+/* (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 + (*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_ligature_set_list (OTF *otf, OTF_Stream *stream, long offset,
+ OTF_LigatureSet **ligset)
+{
+ char *errfmt = "LigatureSet%s";
+ int errret = 0;
+ int count;
+ int i;
+
+ READ_UINT16 (stream, count);
+ if (! count)
+ return errret;
+ OTF_MALLOC (*ligset, count, "");
+ for (i = 0; i < count; i++)
+ READ_OFFSET (stream, (*ligset)[i].offset);
+ for (i = 0; i < count; i++)
+ {
+ 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_alternate_set_list (OTF *otf, OTF_Stream *stream, long offset,
+ OTF_AlternateSet **altset)
+{
+ 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 (*altset, count, "");
+ for (i = 0; i < count; i++)
+ READ_OFFSET (stream, (*altset)[i].offset);
+ for (i = 0; i < count; i++)
+ {
+ 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
+read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset,
+ unsigned type, OTF_LookupSubTableGSUB *subtable)
+{
+ char errfmt[256];
+ int errret = -1;
+
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:
{
if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
return -1;
- READ_INT16 (stream, subtable->sub.gsub.single1.DeltaGlyphID);
+ READ_INT16 (stream, subtable->u.single1.DeltaGlyphID);
}
else if (subtable->Format == 2)
{
if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
return -1;
- subtable->sub.gsub.single2.GlyphCount
- = read_glyph_ids (otf, stream, &subtable->sub.gsub.single2.Substitute,
- 0);
- if (! subtable->sub.gsub.single2.GlyphCount)
+ subtable->u.single2.GlyphCount
+ = read_glyph_ids (otf, stream, &subtable->u.single2.Substitute,
+ 0, -1);
+ if (! subtable->u.single2.GlyphCount)
return -1;
}
else
if (subtable->Format == 1)
{
read_coverage (otf, stream, offset, &subtable->Coverage);
- subtable->sub.gsub.multiple1.SequenceCount
+ subtable->u.multiple1.SequenceCount
= read_sequence (otf, stream, offset,
- &subtable->sub.gsub.multiple1.Sequence);
+ &subtable->u.multiple1.Sequence);
}
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->sub.gsub.ligature1.LigatureSet));
- if (count < 0)
+ if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
+ return -1;
+ subtable->u.ligature1.LigSetCount
+ = read_ligature_set_list (otf, stream, offset,
+ &subtable->u.ligature1.LigatureSet);
+ if (! subtable->u.ligature1.LigSetCount)
return -1;
- subtable->sub.gsub.ligature1.LigSetCount = (unsigned) count;
+ }
+ 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)");
case 6:
if (subtable->Format == 1)
{
- read_coverage (otf, stream, offset, &subtable->Coverage);
- subtable->sub.gsub.chain_context1.ChainSubRuleSetCount
- = (read_chain_subrule_set
- (otf, stream, offset,
- &subtable->sub.gsub.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->sub.gsub.chain_context2.Backtrack);
- read_class_def (otf, stream, offset,
- &subtable->sub.gsub.chain_context2.Input);
- read_class_def (otf, stream, offset,
- &subtable->sub.gsub.chain_context2.LookAhead);
- subtable->sub.gsub.chain_context2.ChainSubClassSetCnt
- = (read_chain_subclass_set
- (otf, stream, offset,
- &subtable->sub.gsub.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->sub.gsub.chain_context3.Backtrack));
- if (count < 0)
- return -1;
- subtable->sub.gsub.chain_context3.BacktrackGlyphCount
- = (unsigned) count;
- count = (read_coverage_list
- (otf, stream, offset,
- &subtable->sub.gsub.chain_context3.Input));
- if (count <= 0)
- return -1;
- subtable->sub.gsub.chain_context3.InputGlyphCount
- = (unsigned) count;
- subtable->Coverage = subtable->sub.gsub.chain_context3.Input[0];
- count = (read_coverage_list
- (otf, stream, offset,
- &subtable->sub.gsub.chain_context3.LookAhead));
- subtable->sub.gsub.chain_context3.LookaheadGlyphCount
- = (unsigned) count;
- subtable->sub.gsub.chain_context3.SubstCount
- = (read_subst_lookup_record
- (otf, stream,
- &subtable->sub.gsub.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_Stream *stream)
+{
+ return read_gsub_gpos_table (otf, stream, 1);
+}
+
\f
-/* GPOS */
+/* (1-10) "GPOS" table */
static int
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++)
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);
int errret = -1;
OTF_StreamState state;
int i;
-
+
READ_OFFSET (stream, array->offset);
SAVE_STREAM (stream, state);
SEEK_STREAM (stream, offset + array->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,
return rec;
}
-
-static int
-read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
- long offset, unsigned type,
- OTF_LookupSubTable *subtable)
-{
- char *errfmt = "GPOS LookupSubTable%s";
- int errret = -1;
-
- SEEK_STREAM (stream, offset);
- READ_UINT16 (stream, subtable->Format);
- switch (type)
- {
- case 1:
-#if 0
- if (subtable->Format == 1)
- {
- read_coverage (otf, stream, offset, &subtable->Coverage);
- subtable->sub.gsub.single1.DeltaGlyphID = READ_INT16 (stream);
- }
- else if (subtable->Format == 2)
- {
- read_coverage (otf, stream, offset, &subtable->Coverage);
- subtable->sub.gsub.single2.GlyphCount
- = read_glyph_ids (otf, stream,
- &subtable->sub.gsub.single2.Substitute, 0);
- }
- else
- OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
-#endif
- break;
-
- case 2:
- if (subtable->Format == 1)
- {
- read_coverage (otf, stream, offset, &subtable->Coverage);
- }
- else if (subtable->Format == 2)
- {
- SEEK_STREAM (stream, offset + 2);
- read_coverage (otf, stream, offset, &subtable->Coverage);
- READ_UINT16 (stream, subtable->sub.gpos.pair2.ValueFormat1);
- READ_UINT16 (stream, subtable->sub.gpos.pair2.ValueFormat2);
- read_class_def (otf, stream, offset,
- &subtable->sub.gpos.pair2.ClassDef1);
- read_class_def (otf, stream, offset,
- &subtable->sub.gpos.pair2.ClassDef2);
- READ_UINT16 (stream, subtable->sub.gpos.pair2.Class1Count);
- READ_UINT16 (stream, subtable->sub.gpos.pair2.Class2Count);
- subtable->sub.gpos.pair2.Class1Record
- = read_class1_record_list (otf, stream, offset,
- subtable->sub.gpos.pair2.Class1Count,
- subtable->sub.gpos.pair2.ValueFormat1,
- subtable->sub.gpos.pair2.Class2Count,
- subtable->sub.gpos.pair2.ValueFormat2);
- }
- else
- OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
- break;
-
- case 4:
- if (subtable->Format == 1)
- {
- read_coverage (otf, stream, offset, &subtable->Coverage);
- read_coverage (otf, stream, offset,
- &subtable->sub.gpos.mark_base1.BaseCoverage);
- READ_UINT16 (stream, subtable->sub.gpos.mark_base1.ClassCount);
- read_mark_array (otf, stream, offset,
- &subtable->sub.gpos.mark_base1.MarkArray);
- read_base_array (otf, stream, offset,
- subtable->sub.gpos.mark_base1.ClassCount,
- &subtable->sub.gpos.mark_base1.BaseArray);
- }
- else
- OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
- break;
-
- case 6:
-#if 0
- if (subtable->Format == 1)
- {
- read_coverage (otf, stream, offset,
- &subtable->sub.gsub.chain_context1.Coverage);
- subtable->sub.gsub.chain_context1.ChainSubRuleSetCount
- = (read_chain_subrule_set
- (otf, stream, offset,
- &subtable->sub.gsub.chain_context1.ChainSubRuleSet));
- }
- else if (subtable->Format == 2)
- {
- read_coverage (otf, stream, offset,
- &subtable->sub.gsub.chain_context2.Coverage);
- read_class_def (otf, stream, offset,
- &subtable->sub.gsub.chain_context2.Backtrack);
- read_class_def (otf, stream, offset,
- &subtable->sub.gsub.chain_context2.Input);
- read_class_def (otf, stream, offset,
- &subtable->sub.gsub.chain_context2.LookAhead);
- subtable->sub.gsub.chain_context2.ChainSubClassSetCnt
- = (read_chain_subclass_set
- (otf, stream, offset,
- &subtable->sub.gsub.chain_context2.ChainSubClassSet));
- }
- else if (subtable->Format == 3)
- {
- subtable->sub.gsub.chain_context3.BacktrackGlyphCount
- = (read_coverage_list
- (otf, stream, offset,
- &subtable->sub.gsub.chain_context3.Backtrack));
- subtable->sub.gsub.chain_context3.InputGlyphCount
- = (read_coverage_list
- (otf, stream, offset,
- &subtable->sub.gsub.chain_context3.Input));
- subtable->sub.gsub.chain_context3.LookaheadGlyphCount
- = (read_coverage_list
- (otf, stream, offset,
- &subtable->sub.gsub.chain_context3.LookAhead));
- subtable->sub.gsub.chain_context3.SubstCount
- = (read_subst_lookup_record
- (otf, stream,
- &subtable->sub.gsub.chain_context3.SubstLookupRecord));
- }
- else
- OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
-#endif
-
- default:
- OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)");
- }
- return 0;
-}
-
-
-static void *
-read_gpos_table (OTF *otf, OTF_Stream *stream)
-{
- 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;
-}
-
-\f
-#if 0
-/* BASE */
-
-static OTF_BASE *
-read_base_table (OTF_Stream *stream, long offset)
-{
- OTF_BASE *base;
-
- OTF_MALLOC (base, 1);
-
- return base;
-}
-
-\f
-/* JSTF */
-
-static OTF_JSTF *
-read_jstf_table (OTF_Stream *stream, long offset)
-{
- OTF_JSTF *jstf;
-
- OTF_MALLOC (jstf, 1);
-
- return jstf;
-}
-#endif
-\f
-/* 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)
+static unsigned
+read_entry_exit_list (OTF *otf, OTF_Stream *stream, long offset,
+ OTF_EntryExitRecord **rec)
{
- char *errfmt = "CaretValue%s";
- int errret = -1;
+ char *errfmt = "EntryExitSet%s";
+ int errret = 0;
+ unsigned count;
+ int i;
+ OTF_StreamState state;
- 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_UINT16 (stream, count);
+ if (! count)
+ OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+ OTF_MALLOC (*rec, count, "");
+ for (i = 0; i < count; i++)
{
- READ_INT16 (stream, caret->f.f3.Coordinate);
- if (read_device_table (otf, stream, offset + caret->offset,
- &caret->f.f3.DeviceTable) < 0)
+ 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;
}
- else
- OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)");
- return 0;
+ RESTORE_STREAM (stream, state);
+ return count;
}
static int
-read_lig_caret_list (OTF *otf, OTF_Stream *stream, long offset,
- OTF_LigCaretList *list)
+read_ligature_attach (OTF *otf, OTF_Stream *stream, long offset,
+ unsigned ClassCount, OTF_LigatureAttach *attach)
{
- char *errfmt = "LigCaretList%s";
- int errret = -1;
+ char *errfmt = "LigatureAttach%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++)
+ SEEK_STREAM (stream, offset + attach->offset);
+ READ_UINT16 (stream, attach->ComponentCount);
+ OTF_MALLOC (attach->ComponentRecord, attach->ComponentCount, "");
+ for (i = 0; i < attach->ComponentCount; 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;
+ 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_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header)
+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_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_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 void *
-read_gdef_table (OTF *otf, OTF_Stream *stream)
+static int
+read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
+ long offset, unsigned type,
+ OTF_LookupSubTableGPOS *subtable)
{
- char *errfmt = "GDEF%s";
- void *errret = NULL;
- OTF_GDEF *gdef;
+ char errfmt[256];
+ int errret = -1;
- 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)
+ SEEK_STREAM (stream, offset);
+ READ_UINT16 (stream, subtable->Format);
+ sprintf (errfmt, "GPOS Lookup %d-%d%%s", type, subtable->Format);
+ switch (type)
{
- gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef;
- read_class_def_without_offset (otf, stream, &gdef->mark_attach_class_def);
- }
+ case 1:
+ if (subtable->Format == 1)
+ {
+ 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;
- return gdef;
-}
+ 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;
-\f
+ 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;
-/* cmap */
+ 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;
-static void *
-read_cmap_table (OTF *otf, OTF_Stream *stream)
-{
- char *errfmt = "cmap%s";
- void *errret = NULL;
- OTF_cmap *cmap;
- int i;
+ case 4:
+ if (subtable->Format == 1)
+ {
+ 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_anchor_array (otf, stream, offset,
+ subtable->u.mark_base1.ClassCount,
+ &subtable->u.mark_base1.BaseArray);
+ }
+ else
+ OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+ break;
- 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;
+ 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;
- 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)
+ case 6:
+ if (subtable->Format == 1)
{
- READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length);
- READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language);
+ 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)");
+ break;
+
+ case 7:
+ if (subtable->Format == 1)
{
- READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language);
+ if (read_context1 (otf, stream, offset, &subtable->Coverage,
+ &subtable->u.context1) < 0)
+ return errret;
}
- switch (format)
+ else if (subtable->Format == 2)
{
- 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;
+ 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)");
+ break;
- case 4:
- {
- OTF_EncodingSubtable4 *sub4;
- int segCount;
- int j;
- unsigned dummy;
+ case 8:
+ if (subtable->Format == 1)
+ {
+ if (read_chain_context1 (otf, stream, offset, &subtable->Coverage,
+ &subtable->u.chain_context1) < 0)
+ return errret;
+ }
+ else if (subtable->Format == 2)
+ {
+ if (read_chain_context2 (otf, stream, offset, &subtable->Coverage,
+ &subtable->u.chain_context2) < 0)
+ return errret;
+ }
+ else if (subtable->Format == 3)
+ {
+ 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;
- 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]);
- }
+ 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)");
+ break;
+
+ default:
+ OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)");
}
- return cmap;
+ return 0;
+}
+
+static void *
+read_gpos_table (OTF *otf, OTF_Stream *stream)
+{
+ return read_gsub_gpos_table (otf, stream, 0);
}
\f
+#if 0
+/* BASE */
+
+static OTF_BASE *
+read_base_table (OTF_Stream *stream, long offset)
+{
+ OTF_BASE *base;
+
+ OTF_MALLOC (base, 1);
+
+ return base;
+}
-/* TABLE: name */
+\f
+/* JSTF */
-static char *
-read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec, int bytes)
+static OTF_JSTF *
+read_jstf_table (OTF_Stream *stream, long offset)
{
- char *errfmt = "nameID (%d)";
- void *errret = NULL;
- OTF_StreamState state;
- char *str;
- int i;
- int c;
+ OTF_JSTF *jstf;
- SAVE_STREAM (stream, state);
- SEEK_STREAM (stream, stream->pos + rec->offset);
+ OTF_MALLOC (jstf, 1);
- if (bytes == 1)
- {
- 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++)
- {
- READ_ULONG (stream, c);
- if (c >= 128)
- c = '?';
- str[i] = c;
- }
- }
- str[i] = '\0';
- RESTORE_STREAM (stream, state);
- return str;
+ return jstf;
}
+#endif /* 0 */
+\f
+/*** (1-11) Structure for OTF */
-static void *
-read_name_table (OTF *otf, OTF_Stream *stream)
+int
+read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table)
{
- char *errfmt = "name%s";
- void *errret = NULL;
- OTF_name *name;
+ 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;
- 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;
+ 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;
- 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 < name->count; i++)
+ 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_NameRecord *rec = name->nameRecord + i;
- int nameID = rec->nameID;
+ 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 (nameID <= OTF_max_nameID
- && ! name->name[nameID])
+ if (table_info)
{
- 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);
+ 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;
}
}
- return name;
+ internal_data->header_stream = NULL;
+ free_stream (stream);
+ return 0;
}
-\f
+static OTF_TableInfo *
+get_table_info (OTF *otf, 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';
-}
+\f
+/*** (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 (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 (len < 4
+ || ext[0] != '.'
+ || (ext[1] != 'O' && ext[1] != 'T' && ext[1] != 'o' && ext[1] != 't')
+ || (ext[2] != 'T' && ext[2] != 't')
+ || (ext[3] != 'F' && ext[3] != 'f'))
+ OTF_ERROR (OTF_ERROR_FILE, otf_name);
fp = fopen (otf_name, "r");
if (! fp)
OTF_ERROR (OTF_ERROR_FILE, 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");
}
if (read_header_part (otf, fp) < 0)
{
- otf_close (otf);
+ OTF_close (otf);
fclose (fp);
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;
- //if (otf->filename)
- //free (otf->filename);
if (internal_data)
{
OTF_MemoryRecord *memrec = internal_data->memory_record;
}
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, 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);
-
- if (! tag)
- OTF_ERROR (OTF_ERROR_TABLE, " (unknown)");
-
- 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)");
+ OTF_TableInfo *table_info = get_table_info (otf, name);
- if (*table_info->address)
- return 0;
- if (! table_info->stream)
- OTF_ERROR (OTF_ERROR_TABLE, " (not found)");
- if (! table_info->reader)
- OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)");
+ if (! table_info)
+ return -1;
*table_info->address = (*table_info->reader) (otf, table_info->stream);
free_stream (table_info->stream);
if (! *table_info->address)
{
table_info->reader = NULL;
- OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)");
+ return -1;
}
-
return 0;
}
+
+/*** (2-4) OTF_check_table() */
+
+int
+OTF_check_table (OTF *otf, char *name)
+{
+ return (get_table_info (otf, name) ? 0 : -1);
+}
+
+
+
+\f
+/*** (5) API miscellaneous ***/
+
+OTF_Tag
+OTF_tag (char *name)
+{
+ unsigned char *p = (unsigned char *) name;
+
+ if (! name)
+ return (OTF_Tag) 0;
+ return (OTF_Tag) ((p[0] << 24) | (p[1] << 16) | (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';
+}