+ {
+ 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_TableInfo *table, int gsubp,
+ enum OTF_ReaderFlag flag)
+{
+ OTF_Stream *stream = table->stream;
+ char *errfmt = gsubp ? "GSUB%s" : "GPOS%s";
+ void *errret = NULL;
+ OTF_GSUB_GPOS *gsub_gpos = *table->address;
+
+ if (gsub_gpos)
+ SEEK_STREAM (stream, 10);
+ else
+ {
+ SEEK_STREAM (stream, 0);
+ OTF_CALLOC (gsub_gpos, 1, "");
+ READ_FIXED (stream, gsub_gpos->Version);
+ READ_OFFSET (stream, gsub_gpos->ScriptList.offset);
+ READ_OFFSET (stream, gsub_gpos->FeatureList.offset);
+ READ_OFFSET (stream, gsub_gpos->LookupList.offset);
+ *table->address = gsub_gpos;
+ }
+
+ if (! gsub_gpos->ScriptList.Script
+ && read_script_list (otf, stream, gsub_gpos->ScriptList.offset,
+ &gsub_gpos->ScriptList) < 0)
+ return NULL;
+ if (flag != OTF_READ_SCRIPTS)
+ {
+ if (! gsub_gpos->FeatureList.Feature
+ && read_feature_list (otf, stream, gsub_gpos->FeatureList.offset,
+ &gsub_gpos->FeatureList) < 0)
+ return NULL;
+ if (flag != OTF_READ_FEATURES)
+ {
+ if (! gsub_gpos->LookupList.Lookup
+ && read_lookup_list (otf, stream, gsub_gpos->LookupList.offset,
+ &gsub_gpos->LookupList, gsubp) < 0)
+ return NULL;
+ }
+ }
+
+ return gsub_gpos;
+}
+
+\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);