+ 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;
+