*** empty log message ***
authorhanda <handa>
Thu, 23 Jan 2003 12:38:28 +0000 (12:38 +0000)
committerhanda <handa>
Thu, 23 Jan 2003 12:38:28 +0000 (12:38 +0000)
example/otfdump.c
example/otfview.c
src/otf.h
src/otfdrive.c
src/otferror.c
src/otfopen.c

index 65f5a97..f788c55 100644 (file)
@@ -73,13 +73,15 @@ dump_head_table (int indent, OTF_head *head)
 /* COMMON */
 
 static void
-dump_glyph_ids (OTF_GlyphID *ids, unsigned num)
+dump_glyph_ids (int indent, char *title, OTF_GlyphID *ids, unsigned count)
 {
-  while (num-- > 0)
+  IPRINT ("(%s (count %d)", title, count);
+  while (count-- > 0)
     {
       printf (" #x%04X", *ids);
       ids++;
     }
+  printf (")");
 }
 
 static void
@@ -92,10 +94,8 @@ dump_coverage (int indent, char *title, OTF_Coverage *coverage)
   indent++;
   if (coverage->CoverageFormat == 1)
     {
-      IPRINT ("(GlyphCount %d)", coverage->Count);
-      IPRINT ("(GlyphArray");
-      dump_glyph_ids (coverage->table.GlyphArray, coverage->Count);
-      printf (")");
+      dump_glyph_ids (indent, "GlyphArray", coverage->table.GlyphArray,
+                     coverage->Count);
     }
   else
     {
@@ -223,32 +223,33 @@ dump_class_def (int indent, char *title, OTF_ClassDef *class)
   IPRINT ("(%s (offset #x%04X) (ClassFormat %d)",
          (title ? title : "ClassDef"),
          class->offset, class->ClassFormat);
-  indent++;
-  if (class->ClassFormat == 1)
+  if (class->offset)
     {
-      IPRINT ("(StartGlyph #x%04X)", class->f.f1.StartGlyph);
-      IPRINT ("(GlyphCount %d)", class->f.f1.GlyphCount);
-      IPRINT ("(ClassValueArray");
-      dump_glyph_ids ((OTF_GlyphID *) class->f.f1.ClassValueArray,
-                     class->f.f1.GlyphCount);
-      printf (")");
-    }
-  else if (class->ClassFormat == 2)
-    {
-      int i;
-
-      IPRINT ("(ClassRangeCount %d)", class->f.f2.ClassRangeCount);
-      IPRINT ("(ClassRangeRecord");
       indent++;
-      for (i = 0; i < class->f.f2.ClassRangeCount; i++)
-       IPRINT ("((Start #x%04X) (End #x%04X) (class %d))",
-               class->f.f2.ClassRangeRecord[i].Start,
-               class->f.f2.ClassRangeRecord[i].End,
-               class->f.f2.ClassRangeRecord[i].Class);
-      printf (")");
+      if (class->ClassFormat == 1)
+       {
+         IPRINT ("(StartGlyph #x%04X)", class->f.f1.StartGlyph);
+         dump_glyph_ids (indent, "ClassValueArray",
+                         (OTF_GlyphID *) class->f.f1.ClassValueArray,
+                         class->f.f1.GlyphCount);
+       }
+      else if (class->ClassFormat == 2)
+       {
+         int i;
+
+         IPRINT ("(ClassRangeCount %d)", class->f.f2.ClassRangeCount);
+         IPRINT ("(ClassRangeRecord");
+         indent++;
+         for (i = 0; i < class->f.f2.ClassRangeCount; i++)
+           IPRINT ("((Start #x%04X) (End #x%04X) (class %d))",
+                   class->f.f2.ClassRangeRecord[i].Start,
+                   class->f.f2.ClassRangeRecord[i].End,
+                   class->f.f2.ClassRangeRecord[i].Class);
+         printf (")");
+       }
+      else
+       printf (" UnknownClassFormat");
     }
-  else
-    printf ("UknownClassFormat");
   printf (")");
 }
 
@@ -299,16 +300,30 @@ dump_sequence_list (int indent, OTF_Sequence *sequence, unsigned num)
     {
       IPRINT ("(Sequence (%d) (offset #x%04X)",
              i, sequence[i].offset);
-      indent++;
-      IPRINT ("(GlyphCount %d)", sequence[i].GlyphCount);
-      IPRINT ("(Substitute");
-      dump_glyph_ids (sequence[i].Substitute, sequence[i].GlyphCount);
-      printf ("))");
-      indent--;
+      dump_glyph_ids (indent + 1, "Substitute", sequence[i].Substitute,
+                     sequence[i].GlyphCount);
+      printf (")");
     }
 }
 
 static void
+dump_alternate_set_list (int indent, OTF_AlternateSet *altset, unsigned num)
+{
+  int i;
+
+  IPRINT ("(AlternateSetCount %d)", num);
+  for (i = 0; i < num; i++)
+    {
+      IPRINT ("(AlternateSet (%d) (offset #x%04X)",
+             i, altset[i].offset);
+      dump_glyph_ids (indent + 1, "Alternate", altset[i].Alternate,
+                     altset[i].GlyphCount);
+      printf (")");
+    }
+}
+
+
+static void
 dump_ligature_set_list (int indent, OTF_LigatureSet *ligset, unsigned num)
 {
   int i, j;
@@ -326,12 +341,9 @@ dump_ligature_set_list (int indent, OTF_LigatureSet *ligset, unsigned num)
          indent++;
          IPRINT ("(LigGlyph #x%04X)",
                  ligset[i].Ligature[j].LigGlyph);
-         IPRINT ("(ComCount %d)",
-                 ligset[i].Ligature[j].CompCount);
-         IPRINT ("(Component");
-         dump_glyph_ids (ligset[i].Ligature[j].Component,
+         dump_glyph_ids (indent, "Component", ligset[i].Ligature[j].Component,
                          ligset[i].Ligature[j].CompCount - 1);
-         printf ("))");
+         printf (")");
          indent--;
        }
       indent--;
@@ -401,17 +413,17 @@ dump_mark_array (int indent, OTF_MarkArray *array)
 }
 
 static void
-dump_base_array (int indent, unsigned ClassCount, OTF_BaseArray *array)
+dump_anchor_array (int indent, unsigned ClassCount, OTF_AnchorArray *array)
 {
   int i, j;
 
-  IPRINT ("(BaseArray (BaseCount %d)", array->BaseCount);
+  IPRINT ("(AnchorArray (Count %d)", array->Count);
   indent++;
-  for (i = 0; i < array->BaseCount; i++)
+  for (i = 0; i < array->Count; i++)
     {
-      IPRINT ("(BaseRecord (%d) ", i);
+      IPRINT ("(AnchorRecord (%d) ", i);
       for (j = 0; j < ClassCount; j++)
-       dump_anchor (indent + 1, array->BaseRecord[i].BaseAnchor + j);
+       dump_anchor (indent + 1, array->AnchorRecord[i].Anchor + j);
       printf (")");
     }
   printf (")");
@@ -419,15 +431,14 @@ dump_base_array (int indent, unsigned ClassCount, OTF_BaseArray *array)
 
 
 static void
-dump_subst_lookup_record_list (int indent,
-                              OTF_SubstLookupRecord *rec, unsigned num)
+dump_lookup_record_list (int indent, OTF_LookupRecord *rec, unsigned num)
 {
   int i;
 
-  IPRINT ("(SubstCount %d)", num);
+  IPRINT ("(LookupCount %d)", num);
   for (i = 0; i < num; i++)
     {
-      IPRINT ("(SubstLookupRecord (%d)", i);
+      IPRINT ("(LookupRecord (%d)", i);
       indent++;
       IPRINT ("(SequenceIndex %d)", rec[i].SequenceIndex);
       IPRINT ("(LookupListIndex %d))", rec[i].LookupListIndex);
@@ -473,6 +484,151 @@ dump_lookup_list (int indent, OTF_LookupList *list, int gsub)
   printf (")");
 }
 
+static void
+dump_rule_list (int indent, OTF_Rule *rule, int count)
+{
+  int i;
+
+  IPRINT ("(RuleCount %d)", count);
+  for (i = 0; i < count; i++)
+    {
+      IPRINT ("(Rule (%d)", i);
+      indent++;
+      IPRINT ("(GlyphCount %d)", rule[i].GlyphCount);
+      IPRINT ("(LookupCount %d)", rule[i].LookupCount);
+      dump_glyph_ids (indent, "Input", rule[i].Input, rule[i].GlyphCount - 1);
+      dump_lookup_record_list (indent, rule[i].LookupRecord,
+                              rule[i].LookupCount);
+      printf (")");
+      indent--;
+    }
+}
+
+static void
+dump_rule_set_list (int indent, OTF_RuleSet *set, int count)
+{
+  int i;
+
+  IPRINT ("(RuleSetCount %d)", count);
+  for (i = 0; i < count; i++)
+    {
+      IPRINT ("(RuleSet (%d)", i);
+      dump_rule_list (indent + 1, set[i].Rule, set[i].RuleCount);
+      printf (")");
+    }
+}
+
+static void
+dump_class_rule_list (int indent, OTF_ClassRule *rule, int count)
+{
+  int i, j;
+
+  IPRINT ("(ClassRuleCnt %d)", count);
+  for (i = 0; i < count; i++)
+    {
+      IPRINT ("(ClassRule (%d)", i);
+      indent++;
+      IPRINT ("(GlyphCount %d)", rule[i].GlyphCount);
+      IPRINT ("(LookupCount %d)", rule[i].LookupCount);
+      IPRINT ("(Class");
+      for (j = 0; j < rule[i].GlyphCount - 1; j++)
+       printf (" %d", rule[i].Class[j]);
+      printf (")");
+      dump_lookup_record_list (indent, rule[i].LookupRecord,
+                              rule[i].LookupCount);
+      printf (")");
+      indent--;
+    }
+}
+
+static void
+dump_class_set_list (int indent, OTF_ClassSet *set, int count)
+{
+  int i;
+
+  IPRINT ("(ClassSetCount %d)", count);
+  for (i = 0; i < count; i++)
+    if (set[i].offset)
+      {
+       IPRINT ("(ClassSet (%d)", i);
+       dump_class_rule_list (indent + 1, set[i].ClassRule,
+                             set[i].ClassRuleCnt);
+       printf (")");
+      }
+}
+
+static void
+dump_chain_rule_list (int indent, OTF_ChainRule *rule, int count)
+{
+  int i;
+
+  IPRINT ("(ChainRuleCount %d)", count);
+  for (i = 0; i < count; i++)
+    {
+      IPRINT ("(ChainRule (%d)", i);
+      dump_glyph_ids (indent + 1, "Backtrack",
+                     rule[i].Backtrack, rule[i].BacktrackGlyphCount);
+      dump_glyph_ids (indent + 1, "Input",
+                     rule[i].Input, rule[i].InputGlyphCount - 1);
+      dump_glyph_ids (indent + 1, "LookAhead",
+                     rule[i].LookAhead, rule[i].LookaheadGlyphCount);
+      dump_lookup_record_list (indent + 1, rule[i].LookupRecord,
+                              rule[i].LookupCount);
+      printf (")");
+    }
+}
+
+static void
+dump_chain_rule_set_list (int indent, OTF_ChainRuleSet *set, int count)
+{
+  int i;
+
+  IPRINT ("(ChainRuleSetCount %d)", count);
+  for (i = 0; i < count; i++)
+    {
+      IPRINT ("(ChainRuleSet (%d)", i);
+      dump_chain_rule_list (indent + 1,
+                           set[i].ChainRule, set[i].ChainRuleCount);
+      printf (")");
+    }
+}
+
+static void
+dump_chain_class_rule_list (int indent, OTF_ChainClassRule *rule, int count)
+{
+  int i;
+
+  IPRINT ("(ChainClassRuleCount %d)", count);
+  for (i = 0; i < count; i++)
+    {
+      IPRINT ("(ChainClassRule (%d)", i);
+      dump_glyph_ids (indent + 1, "Backtrack",
+                     rule[i].Backtrack, rule[i].BacktrackGlyphCount);
+      dump_glyph_ids (indent + 1, "Input",
+                     rule[i].Input, rule[i].InputGlyphCount - 1);
+      dump_glyph_ids (indent + 1, "LookAhead",
+                     rule[i].LookAhead, rule[i].LookaheadGlyphCount);
+      dump_lookup_record_list (indent + 1, rule[i].LookupRecord,
+                              rule[i].LookupCount);
+      printf (")");
+    }
+}
+
+static void
+dump_chain_class_set_list (int indent, OTF_ChainClassSet *set, int count)
+{
+  int i;
+
+  IPRINT ("(ChainClassSetCount %d)", count);
+  for (i = 0; i < count; i++)
+    {
+      IPRINT ("(ChainClassSet (%d)", i);
+      dump_chain_class_rule_list (indent + 1,
+                                 set[i].ChainClassRule,
+                                 set[i].ChainClassRuleCnt);
+      printf (")");
+    }
+}
 
 \f
 /* GSUB */
@@ -495,13 +651,11 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
       else if (subtable->Format == 2)
        {
          dump_coverage (indent, NULL, &subtable->Coverage);
-         IPRINT ("(GlyphCount %d)",
-                 subtable->u.single2.GlyphCount);
-         IPRINT ("(Substitute");
-         dump_glyph_ids (subtable->u.single2.Substitute,
+         dump_glyph_ids (indent, "Substitute", subtable->u.single2.Substitute,
                          subtable->u.single2.GlyphCount);
-         printf (")");
        }
+      else
+       printf (" invalid");
       break;
 
     case 2:
@@ -512,8 +666,21 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
                              subtable->u.multiple1.Sequence,
                              subtable->u.multiple1.SequenceCount);
        }
+      else
+       printf (" invalid");
       break;
       
+    case 3:
+      if (subtable->Format == 1)
+       {
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_alternate_set_list (indent, subtable->u.alternate1.AlternateSet,
+                                  subtable->u.alternate1.AlternateSetCount);
+       }
+      else
+       printf (" invalid");
+      break;
+
     case 4:
       if (subtable->Format == 1)
        {
@@ -522,36 +689,59 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
                                  subtable->u.ligature1.LigatureSet,
                                  subtable->u.ligature1.LigSetCount);
        }
+      else
+       printf (" invalid");
+      break;
+
+    case 5:
+      if (subtable->Format == 1)
+       {
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_rule_set_list (indent, subtable->u.context1.SubRuleSet,
+                             subtable->u.context1.SubRuleSetCount); 
+       }
+      else if (subtable->Format == 2)
+       {
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_class_def (indent, NULL, &subtable->u.context2.ClassDef);
+         dump_class_set_list (indent, subtable->u.context2.SubClassSet,
+                              subtable->u.context2.SubClassSetCnt);
+       }
+      else if (subtable->Format == 3)
+       {
+         dump_coverage_list (indent, "Coverage",
+                             subtable->u.context3.Coverage,
+                             subtable->u.context3.GlyphCount);
+         dump_lookup_record_list (indent,
+                                  subtable->u.context3.LookupRecord,
+                                  subtable->u.context3.SubstCount);
+       }
+      else
+       printf (" invalid");
       break;
 
     case 6:
       if (subtable->Format == 1)
        {
-#if 0
-         read_coverage (fp, offset,
-                        &subtable->u.chain_context1.Coverage);
-         subtable->u.chain_context1.ChainSubRuleSetCount
-           = (read_chain_subrule_set
-              (fp, offset,
-               &subtable->u.chain_context1.ChainSubRuleSet));
-#endif
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_chain_rule_set_list
+           (indent,
+            subtable->u.chain_context1.ChainSubRuleSet,
+            subtable->u.chain_context1.ChainSubRuleSetCount);
        }
       else if (subtable->Format == 2)
        {
-#if 0
-         read_coverage (fp, offset,
-                        &subtable->u.chain_context2.Coverage);
-         read_class_def (fp, offset,
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_class_def (indent, "BacktrackClassDef",
                          &subtable->u.chain_context2.Backtrack);
-         read_class_def (fp, offset,
+         dump_class_def (indent, "InputClassDef",
                          &subtable->u.chain_context2.Input);
-         read_class_def (fp, offset,
+         dump_class_def (indent, "LookaheadClassDef",
                          &subtable->u.chain_context2.LookAhead);
-         subtable->u.chain_context2.ChainSubClassSetCnt
-           = (read_chain_subclass_set
-              (fp, offset,
-               &subtable->u.chain_context2.ChainSubClassSet));
-#endif
+         dump_chain_class_set_list
+           (indent,
+            subtable->u.chain_context2.ChainSubClassSet,
+            subtable->u.chain_context2.ChainSubClassSetCnt);
        }
       else if (subtable->Format == 3)
        {
@@ -564,15 +754,25 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
             subtable->u.chain_context3.Input,
             subtable->u.chain_context3.InputGlyphCount);
          dump_coverage_list
-           (indent, "LookaheaGlyphCount",
+           (indent, "LookaheadGlyphCount",
             subtable->u.chain_context3.LookAhead,
             subtable->u.chain_context3.LookaheadGlyphCount);
-         dump_subst_lookup_record_list
+         dump_lookup_record_list
            (indent,
-            subtable->u.chain_context3.SubstLookupRecord,
+            subtable->u.chain_context3.LookupRecord,
             subtable->u.chain_context3.SubstCount);
        }
+      else
+       printf (" invalid");
+      break;
+
+    case 7:
+    case 8:
+      printf (" not-yet-substcount");
       break;
+
+    default:
+      printf (" invalid");
     }
   printf (")");
 }
@@ -607,30 +807,33 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
   switch (type)
     {
     case 1:
-#if 0
       if (subtable->Format == 1)
        {
-         dump_coverage (indent, NULL, &subtable->u.single1.Coverage);
-         IPRINT ("(DeltaGlyhpID #x%04X)",
-                 subtable->u.single1.DeltaGlyphID);
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         IPRINT ("(ValueFormat #x%04X)",
+                 subtable->u.single1.ValueFormat);
+         dump_value_record (indent, "Value", &subtable->u.single1.Value);
        }
       else if (subtable->Format == 2)
        {
-         dump_coverage (indent, NULL, &subtable->u.single2.Coverage);
-         IPRINT ("(GlyphCount %d)",
-                 subtable->u.single2.GlyphCount);
-         IPRINT ("(Substitute");
-         dump_glyph_ids (subtable->u.single2.Substitute,
-                         subtable->u.single2.GlyphCount);
-         printf (")");
+         int i;
+
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         IPRINT ("(ValueFormat #x%04X)",
+                 subtable->u.single2.ValueFormat);
+         IPRINT ("(ValueCount %d)",
+                 subtable->u.single2.ValueCount);
+         for (i = 0; i < subtable->u.single2.ValueCount; i++)
+           dump_value_record (indent, "Value", &subtable->u.single2.Value[i]);
        }
-#endif
+      else
+       printf (" invalid");
       break;
 
     case 2:
       if (subtable->Format == 1)
        {
-         dump_coverage (indent, NULL, &subtable->Coverage);
+         printf (" not-yet-supported");
        }
       else if (subtable->Format == 2)
        {
@@ -652,8 +855,19 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
                                   subtable->u.pair2.Class2Count,
                                   subtable->u.pair2.Class1Record);
        }
+      else
+       printf (" invalid");
       break;
       
+    case 3:
+      if (subtable->Format == 1)
+       {
+         printf (" not-yet-supported");
+       }
+      else
+       printf (" invalid");
+      break;
+
     case 4:
       if (subtable->Format == 1)
        {
@@ -663,43 +877,88 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
          IPRINT ("(ClassCount %d)",
                  subtable->u.mark_base1.ClassCount);
          dump_mark_array (indent, &subtable->u.mark_base1.MarkArray);
-         dump_base_array (indent, subtable->u.mark_base1.ClassCount,
+         dump_anchor_array (indent, subtable->u.mark_base1.ClassCount,
                           &subtable->u.mark_base1.BaseArray);
        }
       break;
 
+    case 5:
+      if (subtable->Format == 1)
+       {
+         printf (" not-yet-supported");
+       }
+      else
+       printf (" invalid");
+      break;
+
     case 6:
       if (subtable->Format == 1)
        {
-#if 0
-         read_coverage (fp, offset,
-                        &subtable->u.chain_context1.Coverage);
-         subtable->u.chain_context1.ChainSubRuleSetCount
-           = (read_chain_subrule_set
-              (fp, offset,
-               &subtable->u.chain_context1.ChainSubRuleSet));
-#endif
+         dump_coverage (indent, "Mark1", &subtable->Coverage);
+         dump_coverage (indent, "Mark2",
+                        &subtable->u.mark_mark1.Mark2Coverage);
+         IPRINT ("(ClassCount %d)",
+                 subtable->u.mark_mark1.ClassCount);
+         dump_mark_array (indent, &subtable->u.mark_mark1.Mark1Array);
+         dump_anchor_array (indent, subtable->u.mark_mark1.ClassCount,
+                          &subtable->u.mark_mark1.Mark2Array);
+       }
+      else
+       printf (" invalid");
+      break;
+
+    case 7:
+      if (subtable->Format == 1)
+       {
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_rule_set_list (indent, subtable->u.context1.PosRuleSet,
+                             subtable->u.context1.PosRuleSetCount); 
        }
       else if (subtable->Format == 2)
        {
-#if 0
-         read_coverage (fp, offset,
-                        &subtable->u.chain_context2.Coverage);
-         read_class_def (fp, offset,
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_class_def (indent, NULL, &subtable->u.context2.ClassDef);
+         dump_class_set_list (indent, subtable->u.context2.PosClassSet,
+                              subtable->u.context2.PosClassSetCnt);
+       }
+      else if (subtable->Format == 3)
+       {
+         dump_coverage_list (indent, "Coverage",
+                             subtable->u.context3.Coverage,
+                             subtable->u.context3.GlyphCount);
+         dump_lookup_record_list (indent,
+                                  subtable->u.context3.LookupRecord,
+                                  subtable->u.context3.PosCount);
+       }
+      else
+       printf (" invalid");
+      break;
+
+    case 8:
+      if (subtable->Format == 1)
+       {
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_chain_rule_set_list
+           (indent,
+            subtable->u.chain_context1.ChainPosRuleSet,
+            subtable->u.chain_context1.ChainPosRuleSetCount);
+       }
+      else if (subtable->Format == 2)
+       {
+         dump_coverage (indent, NULL, &subtable->Coverage);
+         dump_class_def (indent, "BacktrackClassDef",
                          &subtable->u.chain_context2.Backtrack);
-         read_class_def (fp, offset,
+         dump_class_def (indent, "InputClassDef",
                          &subtable->u.chain_context2.Input);
-         read_class_def (fp, offset,
+         dump_class_def (indent, "LookaheadClassDef",
                          &subtable->u.chain_context2.LookAhead);
-         subtable->u.chain_context2.ChainSubClassSetCnt
-           = (read_chain_subclass_set
-              (fp, offset,
-               &subtable->u.chain_context2.ChainSubClassSet));
-#endif
+         dump_chain_class_set_list
+           (indent,
+            subtable->u.chain_context2.ChainPosClassSet,
+            subtable->u.chain_context2.ChainPosClassSetCnt);
        }
       else if (subtable->Format == 3)
        {
-#if 0
          dump_coverage_list
            (indent, "BackTrackGlyphCount",
             subtable->u.chain_context3.Backtrack,
@@ -712,12 +971,13 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
            (indent, "LookaheaGlyphCount",
             subtable->u.chain_context3.LookAhead,
             subtable->u.chain_context3.LookaheadGlyphCount);
-         dump_subst_lookup_record_list
+         dump_lookup_record_list
            (indent,
-            subtable->u.chain_context3.SubstLookupRecord,
-            subtable->u.chain_context3.SubstCount);
-#endif
+            subtable->u.chain_context3.LookupRecord,
+            subtable->u.chain_context3.PosCount);
        }
+      else
+       printf (" invalid");
       break;
     }
   printf (")");
index d5dc341..79eb728 100644 (file)
@@ -143,7 +143,12 @@ main (int argc, char **argv)
     }
   
   otf = OTF_open (argv[1]);
-  if (! otf)
+  if (! otf
+      || OTF_get_table (otf, "head") < 0
+      || OTF_get_table (otf, "cmap") < 0
+      || OTF_get_table (otf, "GDEF") < 0
+      || OTF_get_table (otf, "GSUB") < 0
+      || OTF_get_table (otf, "GPOS") < 0)
     {
       OTF_perror ("otfview");
       exit (1);
index 56d1a8f..c84368e 100644 (file)
--- a/src/otf.h
+++ b/src/otf.h
@@ -535,58 +535,59 @@ typedef struct
 {
   unsigned SequenceIndex;
   unsigned LookupListIndex;
-} OTF_SubstLookupRecord;
+} OTF_LookupRecord;
 
-typedef struct OTF_SubRuleSet OTF_SubRuleSet;
+typedef struct OTF_RuleSet OTF_RuleSet;
 
 typedef struct
 {
   unsigned SubRuleSetCount;
-  OTF_SubRuleSet *SubRuleSet;
+  OTF_RuleSet *SubRuleSet;     /* [<SubRuleSetCount>] */
 } OTF_GSUB_Context1;
 
-typedef struct OTF_SubRule OTF_SubRule;
+typedef struct OTF_Rule OTF_Rule;
 
-struct OTF_SubRuleSet
+struct OTF_RuleSet
 {
   OTF_Offset offset;
-  unsigned SubRuleCount;
-  OTF_SubRule *SubRule;
+  unsigned RuleCount;
+  OTF_Rule *Rule;              /* [<RuleCount>] */
 };
 
-struct OTF_SubRule
+struct OTF_Rule
 {
   OTF_Offset offset;
   unsigned GlyphCount;
-  unsigned SubstCount;
-  OTF_GlyphID *Input;
-  OTF_SubstLookupRecord *SubstLookupRecord;
+  unsigned LookupCount;
+  OTF_GlyphID *Input;          /* [<GlyphCount> - 1] */
+  OTF_LookupRecord *LookupRecord; /* [<LookupCount>] */
 };
 
-typedef struct OTF_SubClassSet OTF_SubClassSet;
+typedef struct OTF_ClassSet OTF_ClassSet;
 
 typedef struct
 {
   OTF_ClassDef ClassDef;
-  unsigned SubClassSetCount;
-  OTF_SubClassSet *SubClassSet;
+  unsigned SubClassSetCnt;
+  OTF_ClassSet *SubClassSet;   /* [<ClassSetCnt>] */
 } OTF_GSUB_Context2;
 
-typedef struct OTF_SubClassRule OTF_SubClassRule;
+typedef struct OTF_ClassRule OTF_ClassRule;
 
-struct OTF_SubClassSet
+struct OTF_ClassSet
 {
-  unsigned SubClassRuleCnt;
-  OTF_SubClassRule *SubClassRule;
+  OTF_Offset offset;
+  unsigned ClassRuleCnt;
+  OTF_ClassRule *ClassRule;    /* [<ClassRuleCnt>] */
 };
 
-struct OTF_SubClassRule
+struct OTF_ClassRule
 {
   OTF_Offset offset;
   unsigned GlyphCount;
-  unsigned SubstCount;
-  unsigned *Class;
-  OTF_SubstLookupRecord *SubstLookupRecord;
+  unsigned LookupCount;
+  unsigned *Class;             /* [<GlyphCount> - 1] */
+  OTF_LookupRecord *LookupRecord; /* [<LookupCount>] */
 };
 
 typedef struct
@@ -594,27 +595,27 @@ typedef struct
   unsigned GlyphCount;
   unsigned SubstCount;
   OTF_Coverage *Coverage;
-  OTF_SubstLookupRecord *SubstLookupRecord;
+  OTF_LookupRecord *LookupRecord;
 } OTF_GSUB_Context3;
 
-typedef struct OTF_ChainSubRuleSet OTF_ChainSubRuleSet;
+typedef struct OTF_ChainRuleSet OTF_ChainRuleSet;
 
 typedef struct
 {
   unsigned ChainSubRuleSetCount;
-  OTF_ChainSubRuleSet *ChainSubRuleSet;
+  OTF_ChainRuleSet *ChainSubRuleSet;
 } OTF_GSUB_ChainContext1;
 
-typedef struct OTF_ChainSubRule OTF_ChainSubRule;
+typedef struct OTF_ChainRule OTF_ChainRule;
 
-struct OTF_ChainSubRuleSet
+struct OTF_ChainRuleSet
 {
   OTF_Offset offset;
-  unsigned ChainSubRuleCount;
-  OTF_ChainSubRule *ChainSubRule;
+  unsigned ChainRuleCount;
+  OTF_ChainRule *ChainRule;
 };
 
-struct OTF_ChainSubRule
+struct OTF_ChainRule
 {
   OTF_Offset offset;
   unsigned BacktrackGlyphCount;
@@ -623,11 +624,11 @@ struct OTF_ChainSubRule
   OTF_GlyphID *Input;
   unsigned LookaheadGlyphCount;
   OTF_GlyphID *LookAhead;
-  unsigned SubstCount;
-  OTF_SubstLookupRecord *SubstLookupRecord;
+  unsigned LookupCount;
+  OTF_LookupRecord *LookupRecord;
 };
 
-typedef struct OTF_ChainSubClassSet OTF_ChainSubClassSet;
+typedef struct OTF_ChainClassSet OTF_ChainClassSet;
 
 typedef struct
 {
@@ -635,19 +636,19 @@ typedef struct
   OTF_ClassDef Input;
   OTF_ClassDef LookAhead;
   unsigned ChainSubClassSetCnt;
-  OTF_ChainSubClassSet *ChainSubClassSet;
+  OTF_ChainClassSet *ChainSubClassSet;
 } OTF_GSUB_ChainContext2;
 
-typedef struct OTF_ChainSubClassRule OTF_ChainSubClassRule;
+typedef struct OTF_ChainClassRule OTF_ChainClassRule;
 
-struct OTF_ChainSubClassSet
+struct OTF_ChainClassSet
 {
   OTF_Offset offset;
-  unsigned ChainSubClassRuleCnt;
-  OTF_ChainSubClassRule *ChainSubClassRule;
+  unsigned ChainClassRuleCnt;
+  OTF_ChainClassRule *ChainClassRule;
 };
 
-struct OTF_ChainSubClassRule
+struct OTF_ChainClassRule
 {
   OTF_Offset offset;
   unsigned BacktrackGlyphCount;
@@ -656,8 +657,8 @@ struct OTF_ChainSubClassRule
   unsigned *Input;
   unsigned LookaheadGlyphCount;
   unsigned *LookAhead;
-  unsigned SubstCount;
-  OTF_SubstLookupRecord *SubstLookupRecord;
+  unsigned LookupCount;
+  OTF_LookupRecord *LookupRecord;
 };
 
 
@@ -670,7 +671,7 @@ typedef struct
   unsigned LookaheadGlyphCount;
   OTF_Coverage *LookAhead;
   unsigned SubstCount;
-  OTF_SubstLookupRecord *SubstLookupRecord;
+  OTF_LookupRecord *LookupRecord;
 } OTF_GSUB_ChainContext3;
 
 typedef struct
@@ -784,12 +785,15 @@ typedef struct
 
 typedef struct
 {
-  int dummy;
+  unsigned ValueFormat;
+  OTF_ValueRecord Value;  
 } OTF_GPOS_Single1;
 
 typedef struct
 {
-  int dummy;
+  unsigned ValueFormat;
+  unsigned ValueCount;
+  OTF_ValueRecord *Value;      /* [<ValueCount>] */
 } OTF_GPOS_Single2;
 
 typedef struct
@@ -826,22 +830,22 @@ typedef struct
 
 typedef struct
 {
-  OTF_Anchor *BaseAnchor;
-} OTF_BaseRecord;
+  OTF_Anchor *Anchor;
+} OTF_AnchorRecord;
 
 typedef struct
 {
   OTF_Offset offset;
-  unsigned BaseCount;
-  OTF_BaseRecord *BaseRecord;
-} OTF_BaseArray;
+  unsigned Count;
+  OTF_AnchorRecord *AnchorRecord;
+} OTF_AnchorArray;
 
 typedef struct
 {
   OTF_Coverage BaseCoverage;
   unsigned ClassCount;
   OTF_MarkArray MarkArray;
-  OTF_BaseArray BaseArray;
+  OTF_AnchorArray BaseArray;
 } OTF_GPOS_MarkBase1;
 
 typedef struct
@@ -851,37 +855,59 @@ typedef struct
 
 typedef struct
 {
-  int dummy;
+  OTF_Coverage Mark2Coverage;
+  unsigned ClassCount;
+  OTF_MarkArray Mark1Array;
+  OTF_AnchorArray Mark2Array;
 } OTF_GPOS_MarkMark1;
 
+
 typedef struct
 {
-  int dummy;
+  unsigned PosRuleSetCount;
+  OTF_RuleSet *PosRuleSet;
 } OTF_GPOS_Context1;
 
 typedef struct
 {
-  int dummy;
+  OTF_ClassDef ClassDef;
+  unsigned PosClassSetCnt;
+  OTF_ClassSet *PosClassSet;
 } OTF_GPOS_Context2;
 
 typedef struct
 {
-  int dummy;
+  unsigned GlyphCount;
+  unsigned PosCount;
+  OTF_Coverage *Coverage;      /* [<GlyphCount>] */
+  OTF_LookupRecord *LookupRecord;      /* [<PosCount>] */
 } OTF_GPOS_Context3;
 
 typedef struct
 {
-  int dummy;
+  unsigned ChainPosRuleSetCount;
+  OTF_ChainRuleSet *ChainPosRuleSet;
 } OTF_GPOS_ChainContext1;
 
 typedef struct
 {
-  int dummy;
+  OTF_ClassDef Backtrack;
+  OTF_ClassDef Input;
+  OTF_ClassDef LookAhead;
+  unsigned ChainPosClassSetCnt;
+  OTF_ChainClassSet *ChainPosClassSet;
 } OTF_GPOS_ChainContext2;
 
 typedef struct
 {
-  int dummy;
+  unsigned BacktrackGlyphCount;
+  OTF_Coverage *Backtrack;
+  unsigned InputGlyphCount;
+  OTF_Coverage *Input;
+  unsigned LookaheadGlyphCount;
+  OTF_Coverage *LookAhead;
+  unsigned PosCount;
+  OTF_LookupRecord *LookupRecord;
 } OTF_GPOS_ChainContext3;
 
 typedef struct
index 7e3ce4b..336f0d8 100644 (file)
@@ -164,6 +164,34 @@ get_feature_index (OTF_LangSys *LangSys, OTF_FeatureList *FeatureList,
 }
 
 static int
+match_ids (OTF_GlyphString *gstring, int gidx, int count, OTF_GlyphID *ids)
+{
+  int i;
+
+  if (gstring->used - gidx < count)
+    return -1;
+  for (i = 0; i < count; i++)
+    if (gstring->glyphs[gidx + i].glyph_id != ids[i])
+      return -1;
+  return 0;
+}
+
+static int
+match_classes (OTF_ClassDef *class_def, OTF_GlyphString *gstring, int gidx,
+              int count, unsigned *classes)
+{
+  int i;
+
+  if (gstring->used - gidx < count)
+    return -1;
+  for (i = 0; i < count; i++)
+    if (get_class_def (class_def, gstring->glyphs[gidx + i].glyph_id)
+       != classes[i])
+      return -1;
+  return 0;
+}
+
+static int
 lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
             OTF_GlyphString *gstring, int gidx)
 {
@@ -216,27 +244,31 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
          break;
 
        case 3:
-         OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (LookupType not yet supported)");
+         if (subtable->Format == 1)
+           {
+             OTF_GSUB_Alternate1 *alt1 = &subtable->u.alternate1;
+             OTF_AlternateSet *altset = alt1->AlternateSet + coverage_idx;
+
+             g->glyph_id = altset->Alternate[0];
+             gidx++;
+           }
+         else
+           OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
+         break;
 
        case 4:
          if (subtable->Format == 1)
            {
              OTF_GSUB_Ligature1 *lig1 = &subtable->u.ligature1;
              OTF_LigatureSet *ligset = lig1->LigatureSet + coverage_idx;
+             OTF_Ligature *lig;
              int j;
 
              for (j = 0; j < ligset->LigatureCount; j++)
                {
-                 OTF_Ligature *lig = ligset->Ligature + j;
-                 int k;
-
-                 if (gstring->used - gidx < lig->CompCount)
-                   continue;
-                 for (k = 1; k < lig->CompCount; k++)
-                   if (gstring->glyphs[gidx + k].glyph_id
-                       != lig->Component[k - 1])
-                     break;
-                 if (k < lig->CompCount)
+                 lig = ligset->Ligature + j;
+                 if (match_ids (gstring, gidx + 1,
+                                lig->CompCount - 1, lig->Component) < 0)
                    continue;
                  gstring_subst (gstring, gidx, gidx + lig->CompCount,
                                 &lig->LigGlyph, 1);
@@ -248,6 +280,88 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
            OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (invalid SubFormat)");
          break;
              
+       case 5:
+         if (subtable->Format == 1)
+           {
+             OTF_GSUB_Context1 *context1 = &subtable->u.context1; 
+             OTF_RuleSet *set = context1->SubRuleSet + coverage_idx;
+             OTF_Rule *rule;
+             int orig_used;
+             int j, k;
+
+             for (j = 0; j < set->RuleCount; j++)
+               {
+                 rule = set->Rule + j;
+                 if (match_ids (gstring, gidx + 1,
+                                rule->GlyphCount - 1, rule->Input) < 0)
+                   continue;
+                 orig_used = gstring->used;
+                 for (k = 0; k < rule->LookupCount; k++)
+                   lookup_gsub (lookup_list,
+                                rule->LookupRecord[k].LookupListIndex,
+                                gstring,
+                                gidx + rule->LookupRecord[k].SequenceIndex);
+                 gidx += rule->GlyphCount + (gstring->used - orig_used);
+                 break;
+               }
+           }
+         else if (subtable->Format == 2)
+           {
+             OTF_GSUB_Context2 *context2 = &subtable->u.context2; 
+             OTF_ClassSet *set;
+             OTF_ClassRule *rule;
+             unsigned class;
+             int orig_used;
+             int j, k;
+
+             class = get_class_def (&context2->ClassDef, g->glyph_id);
+             set = context2->SubClassSet + class;
+             for (j = 0; j < set->ClassRuleCnt; j++)
+               {
+                 rule = set->ClassRule + j;
+                 if (match_classes (&context2->ClassDef,
+                                    gstring, gidx + 1,
+                                    rule->GlyphCount - 1, rule->Class)
+                     < 0)
+                   continue;
+                 orig_used = gstring->used;
+                 for (k = 0; k < rule->LookupCount; k++)
+                   lookup_gsub (lookup_list,
+                                rule->LookupRecord[k].LookupListIndex,
+                                gstring,
+                                gidx + rule->LookupRecord[k].SequenceIndex);
+                 gidx += rule->GlyphCount + (gstring->used - orig_used);
+                 break;
+               }
+           }
+         else                  /* subtable->Format == 3 */
+           {
+             OTF_GSUB_Context3 *context3 = &subtable->u.context3; 
+             int orig_used;
+             int j, k;
+
+             if (gstring->used - gidx < context3->GlyphCount)
+               continue;
+             /* Start from the secoding coverage_idx because the
+                first one is the same as subtable->Coverage and thus
+                already tested */
+             for (j = 1; j < context3->GlyphCount; j++)
+               if (get_coverage_index (context3->Coverage + j,
+                                       gstring->glyphs[gidx + j].glyph_id)
+                   < 0)
+                 break;
+             if (j < context3->GlyphCount)
+               continue;
+             orig_used = gstring->used;
+             for (k = 0; k < context3->SubstCount; k++)
+               lookup_gsub (lookup_list,
+                            context3->LookupRecord[k].LookupListIndex,
+                            gstring,
+                            gidx + context3->LookupRecord[k].SequenceIndex);
+             gidx += context3->GlyphCount + (gstring->used - orig_used);
+           }
+         break;
+
        case 6:
          if (subtable->Format == 1)
            OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
@@ -274,11 +388,11 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              if (j < context3->BacktrackGlyphCount)
                continue;
 
-             /* Start from the secoding coverage_idx because the
-                first one is the same as subtable->Coverage and thus
+             /* Start from the secode coverage_idx because the first
+                one is the same as subtable->Coverage and thus
                 already tested */
              for (j = 1; j < context3->InputGlyphCount; j++)
-               if (get_coverage_index (context3->Input + j - 1,
+               if (get_coverage_index (context3->Input + j,
                                        gstring->glyphs[gidx + j].glyph_id)
                    < 0)
                  break;
@@ -296,9 +410,9 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              orig_used = gstring->used;
              for (j = 0; j < context3->SubstCount; j++)
                lookup_gsub (lookup_list,
-                            context3->SubstLookupRecord[j].LookupListIndex,
+                            context3->LookupRecord[j].LookupListIndex,
                             gstring,
-                            gidx + context3->SubstLookupRecord[j].SequenceIndex);
+                            gidx + context3->LookupRecord[j].SequenceIndex);
              gidx += context3->InputGlyphCount + (gstring->used - orig_used);
            }
          break;
@@ -421,7 +535,7 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
            {
              OTF_GPOS_MarkBase1 *mark_base1 = &subtable->u.mark_base1;
              OTF_MarkRecord *mark_record;
-             OTF_BaseRecord *base_record;
+             OTF_AnchorRecord *base_record;
              int coverage_idx_base
                = get_coverage_index (&mark_base1->BaseCoverage,
                                      g[-1].glyph_id);
@@ -431,10 +545,10 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              printf ("GPOS 4-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
              mark_record = mark_base1->MarkArray.MarkRecord + coverage_idx;
              base_record
-               = mark_base1->BaseArray.BaseRecord + coverage_idx_base;
+               = mark_base1->BaseArray.AnchorRecord + coverage_idx_base;
              g->f.f4.mark_anchor = &mark_record->MarkAnchor;
              g->f.f4.base_anchor
-               = &base_record->BaseAnchor[mark_record->Class];
+               = &base_record->Anchor[mark_record->Class];
              g->positioning_type = lookup->LookupType;
              break;
            }
@@ -442,7 +556,47 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
            OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
          break;
              
+       case 5:
+         OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
+         break;
+
        case 6:
+         if (gidx < 1)
+           continue;
+         if (subtable->Format == 1)
+           {
+             OTF_GPOS_MarkMark1 *mark_mark1 = &subtable->u.mark_mark1;
+             OTF_MarkRecord *mark1_record;
+             OTF_AnchorRecord *mark2_record;
+             int coverage_idx_base
+               = get_coverage_index (&mark_mark1->Mark2Coverage,
+                                     g[-1].glyph_id);
+
+             if (coverage_idx_base < 0)
+               continue;
+             printf ("GPOS 6-1: c:0x%x g:0x%x\n", g->c, g->glyph_id);
+             mark1_record = mark_mark1->Mark1Array.MarkRecord + coverage_idx;
+             mark2_record
+               = mark_mark1->Mark2Array.AnchorRecord + coverage_idx_base;
+             g->f.f6.mark1_anchor = &mark1_record->MarkAnchor;
+             g->f.f6.mark2_anchor
+               = &mark2_record->Anchor[mark1_record->Class];
+             g->positioning_type = lookup->LookupType;
+             break;
+           }
+         else
+           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
+         break;
+
+       case 7:
+         OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
+         break;
+
+       case 8:
+         OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
+         break;
+
+       case 9:
          OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
          break;
 
index 20db616..aed9623 100644 (file)
@@ -12,10 +12,10 @@ static char *error_string[] =
     "No error",
     "Memory shortage",
     "File error",
-    "Invalid table"
-    "CMAP drive"
-    "GDEF drive"
-    "GSUB drive"
+    "Invalid table",
+    "CMAP drive",
+    "GDEF drive",
+    "GSUB drive",
     "GPOS drive"
   };
 
index d59b0ae..648429f 100644 (file)
@@ -564,21 +564,27 @@ read_lookup_list (OTF *otf, OTF_Stream *stream, long offset,
 }
 
 
+/* 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
@@ -617,7 +623,7 @@ read_coverage (OTF *otf, OTF_Stream *stream, long offset,
   SEEK_STREAM (stream, offset + coverage->offset);
   READ_UINT16 (stream, coverage->CoverageFormat);
   if (coverage->CoverageFormat == 1)
-    count = read_glyph_ids (otf, stream, &coverage->table.GlyphArray, 0);
+    count = read_glyph_ids (otf, stream, &coverage->table.GlyphArray, 0, -1);
   else if (coverage->CoverageFormat == 2)
     count = read_range_records (otf, stream, &coverage->table.RangeRecord);
   else
@@ -629,16 +635,20 @@ read_coverage (OTF *otf, OTF_Stream *stream, long offset,
   return 0;
 }
 
+/* Read list of Coverages from STREAM.  Allocate memory for COVERAGE,
+   and store the Coverages there.  If COUNT is negative, read the
+   number of Coverages at first.  */
+
 static int
 read_coverage_list (OTF *otf, OTF_Stream *stream, long offset,
-                   OTF_Coverage **coverage)
+                   OTF_Coverage **coverage, int count)
 {
   char *errfmt = "Coverage List%s";
   int errret = -1;
-  int count;
   int i;
 
-  READ_UINT16 (stream, count);
+  if (count < 0)
+    READ_UINT16 (stream, count);
   if (! count)
     return 0;
   OTF_MALLOC (*coverage, count, "");
@@ -663,7 +673,7 @@ read_class_def_without_offset (OTF *otf, OTF_Stream *stream,
       READ_GLYPHID (stream, class->f.f1.StartGlyph);
       class->f.f1.GlyphCount
        = (read_glyph_ids
-          (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0));
+          (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0, -1));
       if (! class->f.f1.GlyphCount)
        OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
     }
@@ -689,6 +699,8 @@ read_class_def (OTF *otf, OTF_Stream *stream, long offset, OTF_ClassDef *class)
   OTF_StreamState state;
   
   READ_OFFSET (stream, class->offset);
+  if (! class->offset)
+    return 0;
   SAVE_STREAM (stream, state);
   SEEK_STREAM (stream, offset + class->offset);
   READ_UINT16 (stream, class->ClassFormat);
@@ -696,16 +708,18 @@ read_class_def (OTF *otf, OTF_Stream *stream, long offset, OTF_ClassDef *class)
     {
       READ_GLYPHID (stream, class->f.f1.StartGlyph);
       class->f.f1.GlyphCount
-       = (read_glyph_ids
-          (otf, stream, (OTF_GlyphID **) &class->f.f1.ClassValueArray, 0));
+       = read_glyph_ids (otf, stream,
+                         (OTF_GlyphID **) &class->f.f1.ClassValueArray,
+                         0, -1);
       if (! class->f.f1.GlyphCount)
        return -1;
     }
   else if (class->ClassFormat == 2)
     {
       class->f.f2.ClassRangeCount
-       = (read_range_records
-          (otf, stream, (OTF_RangeRecord **) &class->f.f2.ClassRangeRecord));
+       = read_range_records (otf, stream,
+                             (OTF_RangeRecord **)
+                             &class->f.f2.ClassRangeRecord);
       if (! class->f.f2.ClassRangeCount)
        return -1;
     }
@@ -775,139 +789,176 @@ read_device_table (OTF *otf, OTF_Stream *stream, long offset,
   return 0;
 }
 
-\f
-/* GSUB */
-
-static void *
-read_gsub_table (OTF *otf, OTF_Stream *stream)
+static unsigned
+read_lookup_record_list (OTF *otf, OTF_Stream *stream,
+                        OTF_LookupRecord **record, int count)
 {
-  char *errfmt = "GSUB%s";
-  void *errret = NULL;
-  OTF_GSUB *gsub;
+  char *errfmt = "LookupRecord%s";
+  unsigned errret = 0;
+  int i;
 
-  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;
+  if (count < 0)
+    READ_UINT16 (stream, count);
+  if (! count)
+    OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+  OTF_MALLOC (*record, count, "");
+  for (i = 0; i < count; i++)
+    {
+      READ_UINT16 (stream, (*record)[i].SequenceIndex);
+      READ_UINT16 (stream, (*record)[i].LookupListIndex);
+    }
+  return count;
 }
 
 static unsigned
-read_sequence (OTF *otf, OTF_Stream *stream, long offset, OTF_Sequence **seq)
+read_rule_list (OTF *otf, OTF_Stream *stream, long offset, OTF_Rule **rule)
 {
-  char *errfmt = "Sequence%s";
+  char *errfmt = "List of Rule%s";
   unsigned errret = 0;
+  OTF_StreamState state;
   unsigned count;
   int i;
 
   READ_UINT16 (stream, count);
-  OTF_MALLOC (*seq, count, "");
   if (! count)
     OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+  OTF_MALLOC (*rule, count, "");
   for (i = 0; i < count; i++)
-    READ_OFFSET (stream, (*seq)[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 + (*seq)[i].offset);
-      (*seq)[i].GlyphCount = read_glyph_ids (otf, stream,
-                                            &(*seq)[i].Substitute, 0);
-      if (! (*seq)[i].GlyphCount)
-       return 0;
+      SEEK_STREAM (stream, offset + (*rule)[i].offset);
+      READ_UINT16 (stream, (*rule)[i].GlyphCount);
+      if ((*rule)[i].GlyphCount == 0)
+       OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+      READ_UINT16 (stream, (*rule)[i].LookupCount);
+      if (read_glyph_ids (otf, stream, &(*rule)[i].Input, 0,
+                         (*rule)[i].GlyphCount) < 0)
+       return errret;
+      if (read_lookup_record_list (otf, stream, &(*rule)[i].LookupRecord,
+                                  (*rule)[i].LookupCount) == 0)
+       return errret;
     }
+  RESTORE_STREAM (stream, state);
   return count;
 }
 
-static int
-read_ligature (OTF *otf, OTF_Stream *stream, long offset,
-              OTF_Ligature **ligature)
+
+static unsigned
+read_rule_set_list (OTF *otf, OTF_Stream *stream, long offset,
+                   OTF_RuleSet **set)
 {
-  char *errfmt = "Ligature%s";
-  int errret = -1;
-  int count;
+  char *errfmt = "List of RuleSet%s";
+  unsigned errret = 0;
+  OTF_StreamState state;
+  unsigned count;
   int i;
 
   READ_UINT16 (stream, count);
   if (! count)
-    return 0;
-  OTF_MALLOC (*ligature, count, "");
+    OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+  OTF_MALLOC (*set, count, "");
   for (i = 0; i < count; i++)
-    READ_OFFSET (stream, (*ligature)[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 + (*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)
-       return -1;
+      SEEK_STREAM (stream, offset + (*set)[i].offset);
+      (*set)[i].RuleCount
+       = read_rule_list (otf, stream, offset + (*set)[i].offset,
+                         &(*set)[i].Rule);
+      if (! (*set)[i].RuleCount)
+       return errret;
     }
+  RESTORE_STREAM (stream, state);
   return count;
 }
 
-static int
-read_ligature_set (OTF *otf, OTF_Stream *stream, long offset,
-                  OTF_LigatureSet **ligset)
+static unsigned
+read_class_rule_list (OTF *otf, OTF_Stream *stream, long offset,
+                     OTF_ClassRule **rule)
 {
-  char *errfmt = "LigatureSet%s";
-  int errret = -1;
-  int count;
+  char *errfmt = "ClassRule%s";
+  unsigned errret = 0;
+  OTF_StreamState state;
+  unsigned count;
   int i;
 
   READ_UINT16 (stream, count);
   if (! count)
-    return 0;
-  OTF_MALLOC (*ligset, count, "");
+    OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+  OTF_MALLOC (*rule, count, "");
   for (i = 0; i < count; i++)
-    READ_OFFSET (stream, (*ligset)[i].offset);
+    {
+      READ_OFFSET (stream, (*rule)[i].offset);
+      if (! (*rule)[i].offset)
+       OTF_ERROR (OTF_ERROR_TABLE, " (zero offset)");
+    }
+  SAVE_STREAM (stream, state);
   for (i = 0; i < count; i++)
     {
-      int lig_count;
-
-      SEEK_STREAM (stream, offset + (*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 + (*rule)[i].offset);
+      READ_USHORT (stream, (*rule)[i].GlyphCount);
+      if (! (*rule)[i].GlyphCount)
+       OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+      READ_USHORT (stream, (*rule)[i].LookupCount);
+      if (read_glyph_ids (otf, stream, (OTF_GlyphID **) &(*rule)[i].Class,
+                         0, (*rule)[i].GlyphCount - 1) < 0)
+       return errret;
+      if (read_lookup_record_list (otf, stream, &(*rule)[i].LookupRecord,
+                                  (*rule)[i].LookupCount) == 0)
+       return errret;
     }
+  RESTORE_STREAM (stream, state);
   return count;
 }
 
 static unsigned
-read_subst_lookup_record (OTF *otf, OTF_Stream *stream,
-                         OTF_SubstLookupRecord **record)
+read_class_set_list (OTF *otf, OTF_Stream *stream, long offset,
+                    OTF_ClassSet **set)
 {
-  char *errfmt = "SubstLookupRecord%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 (*record, count, "");
+  OTF_MALLOC (*set, count, "");
   for (i = 0; i < count; i++)
-    {
-      READ_UINT16 (stream, (*record)[i].SequenceIndex);
-      READ_UINT16 (stream, (*record)[i].LookupListIndex);
-    }
+    /* Offset can be zero.  */
+    READ_OFFSET (stream, (*set)[i].offset);
+  SAVE_STREAM (stream, state);
+  for (i = 0; i < count; i++)
+    if ((*set)[i].offset)
+      {
+       SEEK_STREAM (stream, offset + (*set)[i].offset);
+       (*set)[i].ClassRuleCnt
+         = read_class_rule_list (otf, stream, offset + (*set)[i].offset,
+                                 &(*set)[i].ClassRule);
+       if (! (*set)[i].ClassRuleCnt)
+         return errret;
+      }
+  RESTORE_STREAM (stream, state);
   return count;
 }
 
 static unsigned
-read_chain_subrule (OTF *otf, OTF_Stream *stream, long offset,
-                   OTF_ChainSubRule **rule)
+read_chain_rule_list (OTF *otf, OTF_Stream *stream, long offset,
+                     OTF_ChainRule **rule)
 {
-  char *errfmt = "ChainSubRule%s";
+  char *errfmt = "ChainRule%s";
   unsigned errret = 0;
   unsigned count;
   int i;
@@ -922,32 +973,30 @@ read_chain_subrule (OTF *otf, OTF_Stream *stream, long offset,
     {
       SEEK_STREAM (stream, offset + (*rule)[i].offset);
       (*rule)[i].BacktrackGlyphCount
-       = read_glyph_ids (otf, stream, &(*rule)[i].Backtrack, 0);
-      if (! (*rule)[i].BacktrackGlyphCount)
-       return 0;
+       = read_glyph_ids (otf, stream, &(*rule)[i].Backtrack, 0, -1);
       (*rule)[i].InputGlyphCount
-       = read_glyph_ids (otf, stream, &(*rule)[i].Input, -1);
+       = read_glyph_ids (otf, stream, &(*rule)[i].Input, -1, -1);
       if (! (*rule)[i].InputGlyphCount)
-       return 0;
+       OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
       (*rule)[i].LookaheadGlyphCount
-       = read_glyph_ids (otf, stream, &(*rule)[i].LookAhead, 0);
-      if (! (*rule)[i].LookaheadGlyphCount)
-       return 0;
-      (*rule)[i].SubstCount
-       = read_subst_lookup_record (otf, stream, &(*rule)[i].SubstLookupRecord);
-      if (! (*rule)[i].SubstCount)
-       return 0;
+       = read_glyph_ids (otf, stream, &(*rule)[i].LookAhead, 0, -1);
+      (*rule)[i].LookupCount
+       = read_lookup_record_list (otf, stream,
+                                  &(*rule)[i].LookupRecord, -1);
+      if (! (*rule)[i].LookupCount)
+       return errret;
     }
   return count;
 }
 
 
 static unsigned
-read_chain_subrule_set (OTF *otf, OTF_Stream *stream, long offset,
-                       OTF_ChainSubRuleSet **set)
+read_chain_rule_set_list (OTF *otf, OTF_Stream *stream, long offset,
+                    OTF_ChainRuleSet **set)
 {
-  char *errfmt = "ChainSubRuleSet%s";
+  char *errfmt = "ChainRuleSet%s";
   unsigned errret = 0;
+  OTF_StreamState state;
   unsigned count;
   int i;
 
@@ -956,24 +1005,30 @@ read_chain_subrule_set (OTF *otf, OTF_Stream *stream, long offset,
     OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
   OTF_MALLOC (*set, count, "");
   for (i = 0; i < count; i++)
-    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].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_subclass_rule (OTF *otf, OTF_Stream *stream, long offset,
-                         OTF_ChainSubClassRule **rule)
+read_chain_class_rule_list (OTF *otf, OTF_Stream *stream, long offset,
+                           OTF_ChainClassRule **rule)
 {
-  char *errfmt = "ChainSubClassRule%s";
+  char *errfmt = "ChainClassRule%s";
   unsigned errret = 0;
   unsigned count;
   int i;
@@ -983,37 +1038,41 @@ read_chain_subclass_rule (OTF *otf, OTF_Stream *stream, long offset,
     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)");
+    }
   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;
+                         (OTF_GlyphID **) &(*rule)[i].Backtrack, 0, -1);
       (*rule)[i].InputGlyphCount
-       = read_glyph_ids (otf, stream, (OTF_GlyphID **) &(*rule)[i].Input, -1);
+       = read_glyph_ids (otf, stream,
+                         (OTF_GlyphID **) &(*rule)[i].Input, -1, -1);
       if (! (*rule)[i].InputGlyphCount)
-       return 0;
+       OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
       (*rule)[i].LookaheadGlyphCount
-       = read_glyph_ids (otf, stream, (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_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_subclass_set (OTF *otf, OTF_Stream *stream, long offset,
-                        OTF_ChainSubClassSet **set)
+read_chain_class_set_list (OTF *otf, OTF_Stream *stream, long offset,
+                          OTF_ChainClassSet **set)
 {
-  char *errfmt = "ChainSubClassSet%s";
+  char *errfmt = "ChainClassSet%s";
   unsigned errret = 0;
+  OTF_StreamState state;
   unsigned count;
   int i;
 
@@ -1022,30 +1081,169 @@ read_chain_subclass_set (OTF *otf, OTF_Stream *stream, long offset,
     OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
   OTF_MALLOC (*set, count, "");
   for (i = 0; i < count; i++)
+    /* Offset may be zero.  */
     READ_OFFSET (stream, (*set)[i].offset);
+  SAVE_STREAM (stream, state);
+  for (i = 0; i < count; i++)
+    if ((*set)[i].offset)
+      {
+       SEEK_STREAM (stream, offset + (*set)[i].offset);
+       (*set)[i].ChainClassRuleCnt
+         = read_chain_class_rule_list (otf, stream, offset + (*set)[i].offset,
+                                       &(*set)[i].ChainClassRule);
+       if (! (*set)[i].ChainClassRuleCnt)
+         return errret;
+      }
+  RESTORE_STREAM (stream, state);
+  return count;
+}
+
+\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;
+}
+
+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 + (*set)[i].offset);
-      (*set)[i].ChainSubClassRuleCnt
-       = read_chain_subclass_rule (otf, stream, offset + (*set)[i].offset,
-                                   &(*set)[i].ChainSubClassRule);
-      if (! (*set)[i].ChainSubClassRuleCnt)
+      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 = -1;
+  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_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset,
                           unsigned type, OTF_LookupSubTableGSUB *subtable)
 {
-  char *errfmt = "GSUB LookupSubTable%s";
+  char errfmt[256];
   int errret = -1;
   int count;
 
   SEEK_STREAM (stream, offset);
   READ_UINT16 (stream, subtable->Format);
+  sprintf (errfmt, "GSUB Lookup %d-%d%%s", type, subtable->Format);
   switch (type)
     {
     case 1:
@@ -1061,7 +1259,7 @@ read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset,
            return -1;
          subtable->u.single2.GlyphCount
            = read_glyph_ids (otf, stream, &subtable->u.single2.Substitute,
-                             0);
+                             0, -1);
          if (! subtable->u.single2.GlyphCount)
            return -1;
        }
@@ -1082,80 +1280,129 @@ read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset,
       break;
       
     case 3:
+      if (subtable->Format == 1)
+       {
+         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
+           return -1;
+         subtable->u.alternate1.AlternateSetCount
+           = read_alternate_set_list (otf, stream, offset,
+                                      &subtable->u.alternate1.AlternateSet);
+         if (! subtable->u.alternate1.AlternateSetCount)
+           return -1;
+       }
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
 
     case 4:
       if (subtable->Format == 1)
        {
-         read_coverage (otf, stream, offset, &subtable->Coverage);
-         count = (read_ligature_set
-                  (otf, stream, offset,
-                   &subtable->u.ligature1.LigatureSet));
-         if (count < 0)
+         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
+           return -1;
+         subtable->u.ligature1.LigSetCount
+           = read_ligature_set_list (otf, stream, offset,
+                                     &subtable->u.ligature1.LigatureSet);
+         if (! subtable->u.ligature1.LigSetCount)
            return -1;
-         subtable->u.ligature1.LigSetCount = (unsigned) count;
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
 
+    case 5:
+      if (subtable->Format == 1)
+       {
+         OTF_GSUB_Context1 *context1 = &subtable->u.context1; 
+
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         context1->SubRuleSetCount
+           = read_rule_set_list (otf, stream, offset, &context1->SubRuleSet);
+       }
+      else if (subtable->Format == 2)
+       {
+         OTF_GSUB_Context2 *context2 = &subtable->u.context2; 
+
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         read_class_def (otf, stream, offset, &context2->ClassDef);
+         context2->SubClassSetCnt
+           = read_class_set_list (otf, stream, offset, &context2->SubClassSet);
+       }
+      else if (subtable->Format == 3)
+       {
+         OTF_GSUB_Context3 *context3 = &subtable->u.context3;
+
+         READ_USHORT (stream, context3->GlyphCount);
+         if (context3->GlyphCount < 0)
+           OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+         READ_USHORT (stream, context3->SubstCount);
+         if (read_coverage_list (otf, stream, offset,
+                                 &context3->Coverage,
+                                 context3->GlyphCount) < 0)
+           return -1;
+         if (read_lookup_record_list (otf, stream,
+                                      &context3->LookupRecord,
+                                      context3->SubstCount) < 0)
+           return -1;
+       }
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
+      
     case 6:
       if (subtable->Format == 1)
        {
+         OTF_GSUB_ChainContext1 *chain_context1 = &subtable->u.chain_context1;
+
          read_coverage (otf, stream, offset, &subtable->Coverage);
-         subtable->u.chain_context1.ChainSubRuleSetCount
-           = (read_chain_subrule_set
-              (otf, stream, offset,
-               &subtable->u.chain_context1.ChainSubRuleSet));
+         chain_context1->ChainSubRuleSetCount
+           = read_chain_rule_set_list (otf, stream, offset,
+                                       &chain_context1->ChainSubRuleSet);
        }
       else if (subtable->Format == 2)
        {
+         OTF_GSUB_ChainContext2 *chain_context2 = &subtable->u.chain_context2;
+
          read_coverage (otf, stream, offset, &subtable->Coverage);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.chain_context2.Backtrack);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.chain_context2.Input);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.chain_context2.LookAhead);
-         subtable->u.chain_context2.ChainSubClassSetCnt
-           = (read_chain_subclass_set
-              (otf, stream, offset,
-               &subtable->u.chain_context2.ChainSubClassSet));
+         read_class_def (otf, stream, offset, &chain_context2->Backtrack);
+         read_class_def (otf, stream, offset, &chain_context2->Input);
+         read_class_def (otf, stream, offset, &chain_context2->LookAhead);
+         chain_context2->ChainSubClassSetCnt
+           = read_chain_class_set_list (otf, stream, offset,
+                                        &chain_context2->ChainSubClassSet);
        }
       else if (subtable->Format == 3)
        {
-         count = (read_coverage_list
-                  (otf, stream, offset,
-                   &subtable->u.chain_context3.Backtrack));
+         OTF_GSUB_ChainContext3 *chain_context3 = &subtable->u.chain_context3;
+
+         count = read_coverage_list (otf, stream, offset,
+                                     &chain_context3->Backtrack, -1);
          if (count < 0)
            return -1;
-         subtable->u.chain_context3.BacktrackGlyphCount
-           = (unsigned) count;
-         count = (read_coverage_list
-                  (otf, stream, offset,
-                   &subtable->u.chain_context3.Input));
+         chain_context3->BacktrackGlyphCount = (unsigned) count;
+         count = read_coverage_list (otf, stream, offset,
+                                     &chain_context3->Input, -1);
          if (count <= 0)
            return -1;
-         subtable->u.chain_context3.InputGlyphCount
-           = (unsigned) count;
-         subtable->Coverage = subtable->u.chain_context3.Input[0];
-         count = (read_coverage_list
-                  (otf, stream, offset,
-                   &subtable->u.chain_context3.LookAhead));
-         subtable->u.chain_context3.LookaheadGlyphCount
-           = (unsigned) count;
-         subtable->u.chain_context3.SubstCount
-           = (read_subst_lookup_record
-              (otf, stream,
-               &subtable->u.chain_context3.SubstLookupRecord));
+         chain_context3->InputGlyphCount = (unsigned) count;
+         subtable->Coverage = chain_context3->Input[0];
+         count = read_coverage_list (otf, stream, offset,
+                                     &chain_context3->LookAhead, -1);
+         chain_context3->LookaheadGlyphCount = (unsigned) count;
+         chain_context3->SubstCount
+           = read_lookup_record_list (otf, stream,
+                                      &chain_context3->LookupRecord, -1);
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
 
+    case 7:
+    case 8:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");      
+      break;
 
     default:
-       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)");
+      OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)");
     }
   return 0;
 }
@@ -1286,10 +1533,10 @@ read_mark_array (OTF *otf, OTF_Stream *stream, long offset,
 }
 
 static int
-read_base_array (OTF *otf, OTF_Stream *stream, long offset,
-                unsigned ClassCount, OTF_BaseArray *array)
+read_anchor_array (OTF *otf, OTF_Stream *stream, long offset,
+                  unsigned ClassCount, OTF_AnchorArray *array)
 {
-  char *errfmt = "BaseArray%s";
+  char *errfmt = "AnchorArray%s";
   int errret = -1;
   OTF_StreamState state;
   int i, j;
@@ -1297,19 +1544,19 @@ read_base_array (OTF *otf, OTF_Stream *stream, long offset,
   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;
@@ -1342,42 +1589,48 @@ 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_LookupSubTableGPOS *subtable)
 {
-  char *errfmt = "GPOS LookupSubTable%s";
+  char errfmt[256];
   int errret = -1;
+  int count;
 
   SEEK_STREAM (stream, offset);
   READ_UINT16 (stream, subtable->Format);
+  sprintf (errfmt, "GPOS Lookup %d-%d%%s", type, subtable->Format);
   switch (type)
     {
     case 1:
-#if 0
       if (subtable->Format == 1)
        {
-         read_coverage (otf, stream, offset, &subtable->Coverage);
-         subtable->u.single1.DeltaGlyphID = READ_INT16 (stream);
+         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)
        {
-         read_coverage (otf, stream, offset, &subtable->Coverage);
-         subtable->u.single2.GlyphCount
-           = read_glyph_ids (otf, stream,
-                             &subtable->u.single2.Substitute, 0);
+         OTF_GPOS_Single2 *single2 = &subtable->u.single2;
+         int i;
+
+         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)");
-#endif
       break;
 
     case 2:
       if (subtable->Format == 1)
        {
-         read_coverage (otf, stream, offset, &subtable->Coverage);
+         OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
        }
       else if (subtable->Format == 2)
        {
@@ -1402,6 +1655,10 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
       
+    case 3:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+      break;
+
     case 4:
       if (subtable->Format == 1)
        {
@@ -1411,65 +1668,129 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
          READ_UINT16 (stream, subtable->u.mark_base1.ClassCount);
          read_mark_array (otf, stream, offset,
                           &subtable->u.mark_base1.MarkArray);
-         read_base_array (otf, stream, offset,
-                          subtable->u.mark_base1.ClassCount,
-                          &subtable->u.mark_base1.BaseArray);
+         read_anchor_array (otf, stream, offset,
+                            subtable->u.mark_base1.ClassCount,
+                            &subtable->u.mark_base1.BaseArray);
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
 
+    case 5:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+      break;
+
     case 6:
-#if 0
       if (subtable->Format == 1)
        {
+         read_coverage (otf, stream, offset, &subtable->Coverage);
          read_coverage (otf, stream, offset,
-                        &subtable->u.chain_context1.Coverage);
-         subtable->u.chain_context1.ChainSubRuleSetCount
-           = (read_chain_subrule_set
-              (otf, stream, offset,
-               &subtable->u.chain_context1.ChainSubRuleSet));
+                        &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)
+       {
+         OTF_GPOS_Context1 *context1 = &subtable->u.context1; 
+
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         context1->PosRuleSetCount
+           = read_rule_set_list (otf, stream, offset, &context1->PosRuleSet);
        }
       else if (subtable->Format == 2)
        {
-         read_coverage (otf, stream, offset,
-                        &subtable->u.chain_context2.Coverage);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.chain_context2.Backtrack);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.chain_context2.Input);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.chain_context2.LookAhead);
-         subtable->u.chain_context2.ChainSubClassSetCnt
-           = (read_chain_subclass_set
-              (otf, stream, offset,
-               &subtable->u.chain_context2.ChainSubClassSet));
+         OTF_GPOS_Context2 *context2 = &subtable->u.context2; 
+
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         read_class_def (otf, stream, offset, &context2->ClassDef);
+         context2->PosClassSetCnt
+           = read_class_set_list (otf, stream, offset, &context2->PosClassSet);
+         
+       }
+      else if (subtable->Format == 3)
+       {
+         OTF_GPOS_Context3 *context3 = &subtable->u.context3;
+
+         READ_USHORT (stream, context3->GlyphCount);
+         if (context3->GlyphCount < 0)
+           OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+         READ_USHORT (stream, context3->PosCount);
+         if (read_coverage_list (otf, stream, offset,
+                                 &context3->Coverage,
+                                 context3->GlyphCount) < 0)
+           return -1;
+         if (read_lookup_record_list (otf, stream,
+                                      &context3->LookupRecord,
+                                      context3->PosCount) < 0)
+           return -1;
+       }
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
+
+    case 8:
+      if (subtable->Format == 1)
+       {
+         OTF_GPOS_ChainContext1 *chain_context1 = &subtable->u.chain_context1;
+
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         chain_context1->ChainPosRuleSetCount
+           = read_chain_rule_set_list (otf, stream, offset,
+                                       &chain_context1->ChainPosRuleSet);
+       }
+      else if (subtable->Format == 2)
+       {
+         OTF_GPOS_ChainContext2 *chain_context2 = &subtable->u.chain_context2;
+
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         read_class_def (otf, stream, offset, &chain_context2->Backtrack);
+         read_class_def (otf, stream, offset, &chain_context2->Input);
+         read_class_def (otf, stream, offset, &chain_context2->LookAhead);
+         chain_context2->ChainPosClassSetCnt
+           = read_chain_class_set_list (otf, stream, offset,
+                                        &chain_context2->ChainPosClassSet);
        }
       else if (subtable->Format == 3)
        {
-         subtable->u.chain_context3.BacktrackGlyphCount
-           = (read_coverage_list
-              (otf, stream, offset,
-               &subtable->u.chain_context3.Backtrack));
-         subtable->u.chain_context3.InputGlyphCount
-           = (read_coverage_list
-              (otf, stream, offset,
-               &subtable->u.chain_context3.Input));
-         subtable->u.chain_context3.LookaheadGlyphCount
-           = (read_coverage_list
-              (otf, stream, offset,
-               &subtable->u.chain_context3.LookAhead));
-         subtable->u.chain_context3.SubstCount
-           = (read_subst_lookup_record
-              (otf, stream,
-               &subtable->u.chain_context3.SubstLookupRecord));
+         OTF_GPOS_ChainContext3 *chain_context3 = &subtable->u.chain_context3;
+
+         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;
+         subtable->Coverage = chain_context3->Input[0];
+         count = read_coverage_list (otf, stream, offset,
+                                     &chain_context3->LookAhead, -1);
+         chain_context3->LookaheadGlyphCount = (unsigned) count;
+         chain_context3->PosCount
+           = read_lookup_record_list (otf, stream,
+                                      &chain_context3->LookupRecord, -1);
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
-#endif
+      break;
+
+    case 9:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+      break;
 
     default:
-       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)");
+      OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)");
     }
   return 0;
 }
@@ -1524,7 +1845,7 @@ read_jstf_table (OTF_Stream *stream, long offset)
 
   return jstf;
 }
-#endif
+#endif /* 0 */
 \f
 /* GDEF */
 static int
@@ -1966,14 +2287,14 @@ OTF_close (OTF *otf)
 int
 OTF_get_table (OTF *otf, char *name)
 {
-  char *errfmt = "OTF Table Read";
+  char *errfmt = "OTF Table Read%s";
   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)");
+    OTF_ERROR (OTF_ERROR_TABLE, " (invalid table name)");
 
   if (tag == OTF_tag ("head"))
     table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD;
@@ -1988,12 +2309,13 @@ OTF_get_table (OTF *otf, char *name)
   else if (tag == OTF_tag ("GPOS"))
     table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS;
   else
-    OTF_ERROR (OTF_ERROR_TABLE, " (unsupported)");
+    OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported table name)");
 
   if (*table_info->address)
+    /* Already read.  */
     return 0;
   if (! table_info->stream)
-    OTF_ERROR (OTF_ERROR_TABLE, " (not found)");
+    OTF_ERROR (OTF_ERROR_TABLE, " (table not found)");
   if (! table_info->reader)
     OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)");
 
@@ -2003,7 +2325,7 @@ OTF_get_table (OTF *otf, char *name)
   if (! *table_info->address)
     {
       table_info->reader = NULL;
-      OTF_ERROR (OTF_ERROR_TABLE, " (invalid contents)");
+      return errret;
     }
 
   return 0;