*** empty log message ***
authorhanda <handa>
Wed, 26 Feb 2003 13:25:10 +0000 (13:25 +0000)
committerhanda <handa>
Wed, 26 Feb 2003 13:25:10 +0000 (13:25 +0000)
example/otfdump.c
example/otfview.c
src/otf.h
src/otfdrive.c
src/otferror.c
src/otfopen.c

index f788c55..d9d10dc 100644 (file)
@@ -630,6 +630,9 @@ dump_chain_class_set_list (int indent, OTF_ChainClassSet *set, int count)
     }
 }
 
+
+
+
 \f
 /* GSUB */
 
@@ -697,15 +700,15 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
       if (subtable->Format == 1)
        {
          dump_coverage (indent, NULL, &subtable->Coverage);
-         dump_rule_set_list (indent, subtable->u.context1.SubRuleSet,
-                             subtable->u.context1.SubRuleSetCount); 
+         dump_rule_set_list (indent, subtable->u.context1.RuleSet,
+                             subtable->u.context1.RuleSetCount); 
        }
       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);
+         dump_class_set_list (indent, subtable->u.context2.ClassSet,
+                              subtable->u.context2.ClassSetCnt);
        }
       else if (subtable->Format == 3)
        {
@@ -714,7 +717,7 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
                              subtable->u.context3.GlyphCount);
          dump_lookup_record_list (indent,
                                   subtable->u.context3.LookupRecord,
-                                  subtable->u.context3.SubstCount);
+                                  subtable->u.context3.LookupCount);
        }
       else
        printf (" invalid");
@@ -726,22 +729,22 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
          dump_coverage (indent, NULL, &subtable->Coverage);
          dump_chain_rule_set_list
            (indent,
-            subtable->u.chain_context1.ChainSubRuleSet,
-            subtable->u.chain_context1.ChainSubRuleSetCount);
+            subtable->u.chain_context1.ChainRuleSet,
+            subtable->u.chain_context1.ChainRuleSetCount);
        }
       else if (subtable->Format == 2)
        {
          dump_coverage (indent, NULL, &subtable->Coverage);
          dump_class_def (indent, "BacktrackClassDef",
-                         &subtable->u.chain_context2.Backtrack);
+                         &subtable->u.chain_context2.BacktrackClassDef);
          dump_class_def (indent, "InputClassDef",
-                         &subtable->u.chain_context2.Input);
+                         &subtable->u.chain_context2.InputClassDef);
          dump_class_def (indent, "LookaheadClassDef",
-                         &subtable->u.chain_context2.LookAhead);
+                         &subtable->u.chain_context2.LookaheadClassDef);
          dump_chain_class_set_list
            (indent,
-            subtable->u.chain_context2.ChainSubClassSet,
-            subtable->u.chain_context2.ChainSubClassSetCnt);
+            subtable->u.chain_context2.ChainClassSet,
+            subtable->u.chain_context2.ChainClassSetCnt);
        }
       else if (subtable->Format == 3)
        {
@@ -760,7 +763,7 @@ dump_lookup_subtable_gsub (int indent, int index, unsigned type,
          dump_lookup_record_list
            (indent,
             subtable->u.chain_context3.LookupRecord,
-            subtable->u.chain_context3.SubstCount);
+            subtable->u.chain_context3.LookupCount);
        }
       else
        printf (" invalid");
@@ -911,15 +914,15 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
       if (subtable->Format == 1)
        {
          dump_coverage (indent, NULL, &subtable->Coverage);
-         dump_rule_set_list (indent, subtable->u.context1.PosRuleSet,
-                             subtable->u.context1.PosRuleSetCount); 
+         dump_rule_set_list (indent, subtable->u.context1.RuleSet,
+                             subtable->u.context1.RuleSetCount); 
        }
       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.PosClassSet,
-                              subtable->u.context2.PosClassSetCnt);
+         dump_class_set_list (indent, subtable->u.context2.ClassSet,
+                              subtable->u.context2.ClassSetCnt);
        }
       else if (subtable->Format == 3)
        {
@@ -928,7 +931,7 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
                              subtable->u.context3.GlyphCount);
          dump_lookup_record_list (indent,
                                   subtable->u.context3.LookupRecord,
-                                  subtable->u.context3.PosCount);
+                                  subtable->u.context3.LookupCount);
        }
       else
        printf (" invalid");
@@ -940,22 +943,22 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
          dump_coverage (indent, NULL, &subtable->Coverage);
          dump_chain_rule_set_list
            (indent,
-            subtable->u.chain_context1.ChainPosRuleSet,
-            subtable->u.chain_context1.ChainPosRuleSetCount);
+            subtable->u.chain_context1.ChainRuleSet,
+            subtable->u.chain_context1.ChainRuleSetCount);
        }
       else if (subtable->Format == 2)
        {
          dump_coverage (indent, NULL, &subtable->Coverage);
          dump_class_def (indent, "BacktrackClassDef",
-                         &subtable->u.chain_context2.Backtrack);
+                         &subtable->u.chain_context2.BacktrackClassDef);
          dump_class_def (indent, "InputClassDef",
-                         &subtable->u.chain_context2.Input);
+                         &subtable->u.chain_context2.InputClassDef);
          dump_class_def (indent, "LookaheadClassDef",
-                         &subtable->u.chain_context2.LookAhead);
+                         &subtable->u.chain_context2.LookaheadClassDef);
          dump_chain_class_set_list
            (indent,
-            subtable->u.chain_context2.ChainPosClassSet,
-            subtable->u.chain_context2.ChainPosClassSetCnt);
+            subtable->u.chain_context2.ChainClassSet,
+            subtable->u.chain_context2.ChainClassSetCnt);
        }
       else if (subtable->Format == 3)
        {
@@ -974,7 +977,7 @@ dump_lookup_subtable_gpos (int indent, int index, unsigned type,
          dump_lookup_record_list
            (indent,
             subtable->u.chain_context3.LookupRecord,
-            subtable->u.chain_context3.PosCount);
+            subtable->u.chain_context3.LookupCount);
        }
       else
        printf (" invalid");
index 79eb728..5706e4c 100644 (file)
@@ -13,7 +13,7 @@
 #include <X11/keysym.h>
 #include <X11/Xutil.h>
 
-#define PIXEL_SIZE 20
+#define PIXEL_SIZE 40
 
 //#define FONT_NAME "-adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1"
 #define FONT_NAME "6x13"
@@ -145,10 +145,7 @@ main (int argc, char **argv)
   otf = OTF_open (argv[1]);
   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_get_table (otf, "cmap") < 0)
     {
       OTF_perror ("otfview");
       exit (1);
index c84368e..31ff7b5 100644 (file)
--- a/src/otf.h
+++ b/src/otf.h
@@ -27,7 +27,7 @@ Boston, MA 02111-1307, USA.  */
 /***
     Table of contents:
 
-    (1) Structures for OTF tables and OTF itself
+    (1) Structures for OTF Layout tables and OTF itself
     (1-1) Basic types
     (1-2) "head" table
     (1-3) "name" table
@@ -35,9 +35,10 @@ Boston, MA 02111-1307, USA.  */
     (1-5) Structures common to GDEF, GSUB, and GPOS
     (1-6) "GDEF" table
     (1-7) Structures for ScriptList, FeatureList, and LookupList
-    (1-8) "GSUB" table
-    (1-9) "GPOS" table
-    (1-9) Structure for OTF
+    (1-8) Structures common to GSUB and GPOS
+    (1-9) "GSUB" table
+    (1-10) "GPOS" table
+    (1-11) Structure for OTF
 
     (2) APIs for reading OTF
     (2-1) OTF_open()
@@ -60,7 +61,8 @@ Boston, MA 02111-1307, USA.  */
 
 */
 
-/*** (1) Structures for OTF tables and OTF itself */
+\f
+/*** (1) Structures for OTF Layout tables and OTF itself */
 
 /*** (1-1) Basic types */
 
@@ -464,215 +466,231 @@ typedef struct
   OTF_Lookup *Lookup;
 } OTF_LookupList;
 
-/*** (1-8) "GSUB" table */
+
+/*** (1-8) Structures common to GSUB and GPOS */
+
+/* For SubstLookupRecord (GSUB) and PosLookupRecord (GPOS).  */
 
 typedef struct
 {
-  int DeltaGlyphID;
-} OTF_GSUB_Single1;
+  unsigned SequenceIndex;
+  unsigned LookupListIndex;
+} OTF_LookupRecord;
 
 typedef struct
 {
+  OTF_Offset offset;
   unsigned GlyphCount;
-  OTF_GlyphID *Substitute;
-} OTF_GSUB_Single2;
-
-typedef struct OTF_Sequence OTF_Sequence;
+  unsigned LookupCount;
+  OTF_GlyphID *Input;          /* [<GlyphCount> - 1] */
+  OTF_LookupRecord *LookupRecord; /* [<LookupCount>] */
+} OTF_Rule;
 
 typedef struct
 {
-  unsigned SequenceCount;
-  OTF_Sequence *Sequence;
-} OTF_GSUB_Multiple1;
+  OTF_Offset offset;
+  unsigned RuleCount;
+  OTF_Rule *Rule;              /* [<RuleCount>] */
+} OTF_RuleSet;
 
-struct OTF_Sequence
+typedef struct
 {
   OTF_Offset offset;
   unsigned GlyphCount;
-  OTF_GlyphID *Substitute;
-};
-
-typedef struct OTF_AlternateSet OTF_AlternateSet;
+  unsigned LookupCount;
+  unsigned *Class;             /* [<GlyphCount> - 1] */
+  OTF_LookupRecord *LookupRecord; /* [<LookupCount>] */
+} OTF_ClassRule;
 
 typedef struct
 {
-  unsigned AlternateSetCount;
-  OTF_AlternateSet *AlternateSet;
-} OTF_GSUB_Alternate1;
-
-struct OTF_AlternateSet
-{
   OTF_Offset offset;
-  unsigned GlyphCount;
-  OTF_GlyphID *Alternate;
-};
-
-typedef struct OTF_LigatureSet OTF_LigatureSet;
-typedef struct OTF_Ligature OTF_Ligature;
+  unsigned ClassRuleCnt;
+  OTF_ClassRule *ClassRule;    /* [<ClassRuleCnt>] */
+} OTF_ClassSet;
 
 typedef struct
 {
-  unsigned LigSetCount;
-  OTF_LigatureSet *LigatureSet;
-} OTF_GSUB_Ligature1;
+  OTF_Offset offset;
+  unsigned BacktrackGlyphCount;
+  OTF_GlyphID *Backtrack;
+  unsigned InputGlyphCount;
+  OTF_GlyphID *Input;
+  unsigned LookaheadGlyphCount;
+  OTF_GlyphID *LookAhead;
+  unsigned LookupCount;
+  OTF_LookupRecord *LookupRecord;
+} OTF_ChainRule;
 
-struct OTF_LigatureSet
+typedef struct
 {
   OTF_Offset offset;
-  unsigned LigatureCount;
-  OTF_Ligature *Ligature;
-};
+  unsigned ChainRuleCount;
+  OTF_ChainRule *ChainRule;
+} OTF_ChainRuleSet;
 
-struct OTF_Ligature
+typedef struct
 {
   OTF_Offset offset;
-  OTF_GlyphID LigGlyph;
-  unsigned CompCount;
-  OTF_GlyphID *Component;
-};
+  unsigned BacktrackGlyphCount;
+  unsigned *Backtrack;
+  unsigned InputGlyphCount;
+  unsigned *Input;
+  unsigned LookaheadGlyphCount;
+  unsigned *LookAhead;
+  unsigned LookupCount;
+  OTF_LookupRecord *LookupRecord;
+} OTF_ChainClassRule;
 
 typedef struct
 {
-  unsigned SequenceIndex;
-  unsigned LookupListIndex;
-} OTF_LookupRecord;
+  OTF_Offset offset;
+  unsigned ChainClassRuleCnt;
+  OTF_ChainClassRule *ChainClassRule;
+} OTF_ChainClassSet;
 
-typedef struct OTF_RuleSet OTF_RuleSet;
+
+/* Common to OTF_GSUB/GPOS_Context1/2/3.  */
 
 typedef struct
 {
-  unsigned SubRuleSetCount;
-  OTF_RuleSet *SubRuleSet;     /* [<SubRuleSetCount>] */
-} OTF_GSUB_Context1;
-
-typedef struct OTF_Rule OTF_Rule;
+  unsigned RuleSetCount;
+  OTF_RuleSet *RuleSet;                /* [<RuleSetCount>] */
+} OTF_Context1;
 
-struct OTF_RuleSet
+typedef struct
 {
-  OTF_Offset offset;
-  unsigned RuleCount;
-  OTF_Rule *Rule;              /* [<RuleCount>] */
-};
+  OTF_ClassDef ClassDef;
+  unsigned ClassSetCnt;
+  OTF_ClassSet *ClassSet;      /* [<ClassSetCnt>] */
+} OTF_Context2;
 
-struct OTF_Rule
+typedef struct
 {
-  OTF_Offset offset;
   unsigned GlyphCount;
   unsigned LookupCount;
-  OTF_GlyphID *Input;          /* [<GlyphCount> - 1] */
+  OTF_Coverage *Coverage;      /* [<GlyphCount>] */
   OTF_LookupRecord *LookupRecord; /* [<LookupCount>] */
-};
+} OTF_Context3;
 
-typedef struct OTF_ClassSet OTF_ClassSet;
+
+/* Common to OTF_GSUB/GPOS_ChainContext1/2/3.  */
 
 typedef struct
 {
-  OTF_ClassDef ClassDef;
-  unsigned SubClassSetCnt;
-  OTF_ClassSet *SubClassSet;   /* [<ClassSetCnt>] */
-} OTF_GSUB_Context2;
+  unsigned ChainRuleSetCount;
+  OTF_ChainRuleSet *ChainRuleSet;
+} OTF_ChainContext1;
 
-typedef struct OTF_ClassRule OTF_ClassRule;
-
-struct OTF_ClassSet
+typedef struct
 {
-  OTF_Offset offset;
-  unsigned ClassRuleCnt;
-  OTF_ClassRule *ClassRule;    /* [<ClassRuleCnt>] */
-};
+  OTF_ClassDef BacktrackClassDef;
+  OTF_ClassDef InputClassDef;
+  OTF_ClassDef LookaheadClassDef;
+  unsigned ChainClassSetCnt;
+  OTF_ChainClassSet *ChainClassSet;
+} OTF_ChainContext2;
 
-struct OTF_ClassRule
+typedef struct
 {
-  OTF_Offset offset;
-  unsigned GlyphCount;
+  unsigned BacktrackGlyphCount;
+  OTF_Coverage *Backtrack;
+  unsigned InputGlyphCount;
+  OTF_Coverage *Input;
+  unsigned LookaheadGlyphCount;
+  OTF_Coverage *LookAhead;
   unsigned LookupCount;
-  unsigned *Class;             /* [<GlyphCount> - 1] */
-  OTF_LookupRecord *LookupRecord; /* [<LookupCount>] */
-};
+  OTF_LookupRecord *LookupRecord;
+} OTF_ChainContext3;
+
+/* Common to OTF_GSUB/GPOS.  */
 
 typedef struct
 {
-  unsigned GlyphCount;
-  unsigned SubstCount;
-  OTF_Coverage *Coverage;
-  OTF_LookupRecord *LookupRecord;
-} OTF_GSUB_Context3;
+  OTF_Fixed Version;
+  OTF_ScriptList ScriptList;
+  OTF_FeatureList FeatureList;
+  OTF_LookupList LookupList;
+} OTF_GSUB_GPOS;
 
-typedef struct OTF_ChainRuleSet OTF_ChainRuleSet;
+/*** (1-9) "GSUB" table */
 
 typedef struct
 {
-  unsigned ChainSubRuleSetCount;
-  OTF_ChainRuleSet *ChainSubRuleSet;
-} OTF_GSUB_ChainContext1;
+  int DeltaGlyphID;
+} OTF_GSUB_Single1;
+
+typedef struct
+{
+  unsigned GlyphCount;
+  OTF_GlyphID *Substitute;
+} OTF_GSUB_Single2;
 
-typedef struct OTF_ChainRule OTF_ChainRule;
+typedef struct OTF_Sequence OTF_Sequence;
+
+typedef struct
+{
+  unsigned SequenceCount;
+  OTF_Sequence *Sequence;
+} OTF_GSUB_Multiple1;
 
-struct OTF_ChainRuleSet
+struct OTF_Sequence
 {
   OTF_Offset offset;
-  unsigned ChainRuleCount;
-  OTF_ChainRule *ChainRule;
+  unsigned GlyphCount;
+  OTF_GlyphID *Substitute;
 };
 
-struct OTF_ChainRule
+typedef struct OTF_AlternateSet OTF_AlternateSet;
+
+typedef struct
+{
+  unsigned AlternateSetCount;
+  OTF_AlternateSet *AlternateSet;
+} OTF_GSUB_Alternate1;
+
+struct OTF_AlternateSet
 {
   OTF_Offset offset;
-  unsigned BacktrackGlyphCount;
-  OTF_GlyphID *Backtrack;
-  unsigned InputGlyphCount;
-  OTF_GlyphID *Input;
-  unsigned LookaheadGlyphCount;
-  OTF_GlyphID *LookAhead;
-  unsigned LookupCount;
-  OTF_LookupRecord *LookupRecord;
+  unsigned GlyphCount;
+  OTF_GlyphID *Alternate;
 };
 
-typedef struct OTF_ChainClassSet OTF_ChainClassSet;
+typedef struct OTF_LigatureSet OTF_LigatureSet;
+typedef struct OTF_Ligature OTF_Ligature;
 
 typedef struct
 {
-  OTF_ClassDef Backtrack;
-  OTF_ClassDef Input;
-  OTF_ClassDef LookAhead;
-  unsigned ChainSubClassSetCnt;
-  OTF_ChainClassSet *ChainSubClassSet;
-} OTF_GSUB_ChainContext2;
-
-typedef struct OTF_ChainClassRule OTF_ChainClassRule;
+  unsigned LigSetCount;
+  OTF_LigatureSet *LigatureSet;
+} OTF_GSUB_Ligature1;
 
-struct OTF_ChainClassSet
+struct OTF_LigatureSet
 {
   OTF_Offset offset;
-  unsigned ChainClassRuleCnt;
-  OTF_ChainClassRule *ChainClassRule;
+  unsigned LigatureCount;
+  OTF_Ligature *Ligature;
 };
 
-struct OTF_ChainClassRule
+struct OTF_Ligature
 {
   OTF_Offset offset;
-  unsigned BacktrackGlyphCount;
-  unsigned *Backtrack;
-  unsigned InputGlyphCount;
-  unsigned *Input;
-  unsigned LookaheadGlyphCount;
-  unsigned *LookAhead;
-  unsigned LookupCount;
-  OTF_LookupRecord *LookupRecord;
+  OTF_GlyphID LigGlyph;
+  unsigned CompCount;
+  OTF_GlyphID *Component;
 };
 
+typedef OTF_Context1 OTF_GSUB_Context1;
 
-typedef struct
-{
-  unsigned BacktrackGlyphCount;
-  OTF_Coverage *Backtrack;
-  unsigned InputGlyphCount;
-  OTF_Coverage *Input;
-  unsigned LookaheadGlyphCount;
-  OTF_Coverage *LookAhead;
-  unsigned SubstCount;
-  OTF_LookupRecord *LookupRecord;
-} OTF_GSUB_ChainContext3;
+typedef OTF_Context2 OTF_GSUB_Context2;
+
+typedef OTF_Context3 OTF_GSUB_Context3;
+
+typedef OTF_ChainContext1 OTF_GSUB_ChainContext1;
+
+typedef OTF_ChainContext2 OTF_GSUB_ChainContext2;
+
+typedef OTF_ChainContext3 OTF_GSUB_ChainContext3;
 
 typedef struct
 {
@@ -719,15 +737,9 @@ struct OTF_LookupSubTableGSUB
   } u;
 };
 
-typedef struct
-{
-  OTF_Fixed Version;
-  OTF_ScriptList ScriptList;
-  OTF_FeatureList FeatureList;
-  OTF_LookupList LookupList;
-} OTF_GSUB;
+typedef OTF_GSUB_GPOS OTF_GSUB;
 
-/*** (1-8) "GPOS" table */
+/*** (1-10) "GPOS" table */
 
 enum OTF_ValueFormat
   {
@@ -861,54 +873,17 @@ typedef struct
   OTF_AnchorArray Mark2Array;
 } OTF_GPOS_MarkMark1;
 
+typedef OTF_Context1 OTF_GPOS_Context1;
 
-typedef struct
-{
-  unsigned PosRuleSetCount;
-  OTF_RuleSet *PosRuleSet;
-} OTF_GPOS_Context1;
+typedef OTF_Context2 OTF_GPOS_Context2;
 
-typedef struct
-{
-  OTF_ClassDef ClassDef;
-  unsigned PosClassSetCnt;
-  OTF_ClassSet *PosClassSet;
-} OTF_GPOS_Context2;
+typedef OTF_Context3 OTF_GPOS_Context3;
 
-typedef struct
-{
-  unsigned GlyphCount;
-  unsigned PosCount;
-  OTF_Coverage *Coverage;      /* [<GlyphCount>] */
-  OTF_LookupRecord *LookupRecord;      /* [<PosCount>] */
-} OTF_GPOS_Context3;
+typedef OTF_ChainContext1 OTF_GPOS_ChainContext1;
 
-typedef struct
-{
-  unsigned ChainPosRuleSetCount;
-  OTF_ChainRuleSet *ChainPosRuleSet;
-} OTF_GPOS_ChainContext1;
+typedef OTF_ChainContext2 OTF_GPOS_ChainContext2;
 
-typedef struct
-{
-  OTF_ClassDef Backtrack;
-  OTF_ClassDef Input;
-  OTF_ClassDef LookAhead;
-  unsigned ChainPosClassSetCnt;
-  OTF_ChainClassSet *ChainPosClassSet;
-} OTF_GPOS_ChainContext2;
-
-typedef struct
-{
-  unsigned BacktrackGlyphCount;
-  OTF_Coverage *Backtrack;
-  unsigned InputGlyphCount;
-  OTF_Coverage *Input;
-  unsigned LookaheadGlyphCount;
-  OTF_Coverage *LookAhead;
-  unsigned PosCount;
-  OTF_LookupRecord *LookupRecord;
-} OTF_GPOS_ChainContext3;
+typedef OTF_ChainContext3 OTF_GPOS_ChainContext3;
 
 typedef struct
 {
@@ -948,15 +923,9 @@ struct OTF_LookupSubTableGPOS
   } u;
 };
 
-typedef struct
-{
-  OTF_Fixed Version;
-  OTF_ScriptList ScriptList;
-  OTF_FeatureList FeatureList;
-  OTF_LookupList LookupList;
-} OTF_GPOS;
+typedef OTF_GSUB_GPOS OTF_GPOS;
 
-/*** (1-9) Structure for OTF */
+/*** (1-11) Structure for OTF */
 
 typedef struct
 {
@@ -1281,9 +1250,9 @@ extern OTF_Tag OTF_tag (char *name);
 /***
     Convert OTF tag to name string.
 
-    The OTF_tag_name() function converts OTF tag $TAG to a 5-byte
-    name string (including the terminating NUL), and store it in
-    $NAME.  At least 5-byte space must be at $NAME.  */
+    The OTF_tag_name() function converts OTF tag $TAG to a 5-byte name
+    string (including the terminating NULL), and store it in $NAME.
+    At least 5-byte space must be at $NAME.  */
 
 extern void OTF_tag_name (OTF_Tag tag, char *name);
 
index 336f0d8..e1cf19d 100644 (file)
@@ -1,3 +1,26 @@
+/* otfdrive.c -- OpenType font driver.
+
+Copyright (C) 2003
+  by AIST (National Institute of Advanced Industrial Science and Technology)
+  Registration Number H15PRO???
+
+This file is part of the OTF library.
+
+The OTF library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2, or (at
+your option) any later version.
+
+The OTF library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the OTF library; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -284,7 +307,7 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
          if (subtable->Format == 1)
            {
              OTF_GSUB_Context1 *context1 = &subtable->u.context1; 
-             OTF_RuleSet *set = context1->SubRuleSet + coverage_idx;
+             OTF_RuleSet *set = context1->RuleSet + coverage_idx;
              OTF_Rule *rule;
              int orig_used;
              int j, k;
@@ -315,7 +338,7 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              int j, k;
 
              class = get_class_def (&context2->ClassDef, g->glyph_id);
-             set = context2->SubClassSet + class;
+             set = context2->ClassSet + class;
              for (j = 0; j < set->ClassRuleCnt; j++)
                {
                  rule = set->ClassRule + j;
@@ -353,7 +376,7 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
              if (j < context3->GlyphCount)
                continue;
              orig_used = gstring->used;
-             for (k = 0; k < context3->SubstCount; k++)
+             for (k = 0; k < context3->LookupCount; k++)
                lookup_gsub (lookup_list,
                             context3->LookupRecord[k].LookupListIndex,
                             gstring,
@@ -366,11 +389,61 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
          if (subtable->Format == 1)
            OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
          else if (subtable->Format == 2)
-           OTF_ERROR (OTF_ERROR_GSUB_DRIVE, " (not yet supported)");
+           {
+             OTF_GSUB_ChainContext2 *context2 = &subtable->u.chain_context2;
+             OTF_ChainClassSet *set;
+             unsigned class;
+             int j;
+             int orig_used;
+
+             printf ("GSUB 6-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
+             class = get_class_def (&context2->InputClassDef, g->glyph_id);
+             set = context2->ChainClassSet + class;
+             for (j = 0; j < set->ChainClassRuleCnt; j++)
+               {
+                 OTF_ChainClassRule *rule = set->ChainClassRule + j;
+                 int fore_idx = gidx + rule->InputGlyphCount;
+                 int k;
+
+                 if (gidx < rule->BacktrackGlyphCount
+                     || (gidx + rule->InputGlyphCount
+                         + rule->LookaheadGlyphCount) >= gstring->used)
+                   continue;
+                 for (k = 0; k < rule->BacktrackGlyphCount; k++)
+                   if (get_class_def (&context2->BacktrackClassDef,
+                                      gstring->glyphs[gidx - 1 - k].glyph_id)
+                       != rule->Backtrack[k])
+                     break;
+                 if (k < rule->BacktrackGlyphCount)
+                   continue;
+                 for (k = 1; k < rule->InputGlyphCount; k++)
+                   if (get_class_def (&context2->InputClassDef,
+                                      gstring->glyphs[gidx + k].glyph_id)
+                       != rule->Input[k - 1])
+                     break;
+                 if (k < rule->InputGlyphCount)
+                   continue;
+                 for (k = 0; k < rule->LookaheadGlyphCount; k++)
+                   if (get_class_def (&context2->LookaheadClassDef,
+                                      gstring->glyphs[fore_idx + k].glyph_id)
+                       != rule->LookAhead[k])
+                     break;
+                 if (k < rule->LookaheadGlyphCount)
+                   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->InputGlyphCount + (gstring->used - orig_used);
+                 break;
+               }
+           }
          else
            {
-             OTF_GSUB_ChainContext3 *context3
-               = &subtable->u.chain_context3;
+             OTF_GSUB_ChainContext3 *context3 = &subtable->u.chain_context3;
              int back_gidx = gidx - context3->BacktrackGlyphCount;
              int fore_gidx = gidx + context3->InputGlyphCount;
              int orig_used;
@@ -382,7 +455,7 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
 
              for (j = 0; j < context3->BacktrackGlyphCount; j++)
                if (get_coverage_index (context3->Backtrack + j,
-                                       gstring->glyphs[back_gidx + j].glyph_id)
+                                       gstring->glyphs[gidx - 1 - j].glyph_id)
                    < 0)
                  break;
              if (j < context3->BacktrackGlyphCount)
@@ -408,7 +481,7 @@ lookup_gsub (OTF_LookupList *lookup_list, unsigned lookup_list_index,
                continue;
 
              orig_used = gstring->used;
-             for (j = 0; j < context3->SubstCount; j++)
+             for (j = 0; j < context3->LookupCount; j++)
                lookup_gsub (lookup_list,
                             context3->LookupRecord[j].LookupListIndex,
                             gstring,
@@ -593,7 +666,65 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
          break;
 
        case 8:
-         OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
+         if (subtable->Format == 1)
+           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
+         else if (subtable->Format == 2)
+           {
+             OTF_GPOS_ChainContext2 *context2 = &subtable->u.chain_context2;
+             OTF_ChainClassSet *set;
+             unsigned class;
+             int j;
+             int orig_used;
+
+             printf ("GPOS 8-2: c:0x%x g:0x%x\n", g->c, g->glyph_id);
+             class = get_class_def (&context2->InputClassDef, g->glyph_id);
+             set = context2->ChainClassSet + class;
+             for (j = 0; j < set->ChainClassRuleCnt; j++)
+               {
+                 OTF_ChainClassRule *rule = set->ChainClassRule + j;
+                 int fore_idx = gidx + rule->InputGlyphCount;
+                 int k;
+
+                 if (gidx < rule->BacktrackGlyphCount
+                     || (gidx + rule->InputGlyphCount
+                         + rule->LookaheadGlyphCount) >= gstring->used)
+                   continue;
+                 for (k = 0; k < rule->BacktrackGlyphCount; k++)
+                   if (get_class_def (&context2->BacktrackClassDef,
+                                      gstring->glyphs[gidx - 1 - k].glyph_id)
+                       != rule->Backtrack[k])
+                     break;
+                 if (k < rule->BacktrackGlyphCount)
+                   continue;
+                 for (k = 1; k < rule->InputGlyphCount; k++)
+                   if (get_class_def (&context2->InputClassDef,
+                                      gstring->glyphs[gidx + k].glyph_id)
+                       != rule->Input[k - 1])
+                     break;
+                 if (k < rule->InputGlyphCount)
+                   continue;
+                 for (k = 0; k < rule->LookaheadGlyphCount; k++)
+                   if (get_class_def (&context2->LookaheadClassDef,
+                                      gstring->glyphs[fore_idx + k].glyph_id)
+                       != rule->LookAhead[k])
+                     break;
+                 if (k < rule->LookaheadGlyphCount)
+                   continue;
+
+                 orig_used = gstring->used;
+                 for (k = 0; k < rule->LookupCount; k++)
+                   lookup_gpos (lookup_list,
+                                rule->LookupRecord[k].LookupListIndex,
+                                gstring,
+                                gidx + rule->LookupRecord[k].SequenceIndex);
+                 gidx += rule->InputGlyphCount + (gstring->used - orig_used);
+                 break;
+               }
+           }
+         else if (subtable->Format == 3)
+           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (not yet supported)");
+         else
+           OTF_ERROR (OTF_ERROR_GPOS_DRIVE, " (invalid subformat)");
          break;
 
        case 9:
@@ -619,6 +750,8 @@ lookup_gpos (OTF_LookupList *lookup_list, unsigned lookup_list_index,
 static int
 lookup_cmap (OTF_cmap *cmap, int c)
 {
+  char *errfmt = "cmap driving%s";
+  int errret = -1;
   int i;
 
   if (! cmap || ! cmap->Unicode)
@@ -626,9 +759,6 @@ lookup_cmap (OTF_cmap *cmap, int c)
 
   switch (cmap->Unicode->subtable.format)
     {
-    case 0:
-      break;
-
     case 4:
       {
        OTF_EncodingSubtable4 *sub4 = cmap->Unicode->subtable.f.f4;
@@ -641,11 +771,18 @@ lookup_cmap (OTF_cmap *cmap, int c)
          return 0;
        if (sub4->segments[i].idRangeOffset == 0xFFFF)
          return c + sub4->segments[i].idDelta;
+       if (c == 0xFFFF)
+         return 0;
        return sub4->glyphIdArray[sub4->segments[i].idRangeOffset
                                  + (c - sub4->segments[i].startCount)];
       }
       break;
+
+    default:
+      OTF_ERROR (OTF_ERROR_CMAP_DRIVE, " (not yet supported)");
+      break;
     }
+
   return 0;
 }
 
@@ -665,8 +802,11 @@ OTF_drive_cmap (OTF *otf, OTF_GlyphString *gstring)
 
   cmap = otf->cmap;
   for (i = 0; i < gstring->used; i++)
+    {
       gstring->glyphs[i].glyph_id = lookup_cmap (cmap, gstring->glyphs[i].c);
-
+      if (gstring->glyphs[i].glyph_id < 0)
+       return -1;
+    }
   return 0;
 }
 
@@ -712,12 +852,12 @@ OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
 
   if (! otf->gsub
       && OTF_get_table (otf, "GSUB") < 0)
-    return -1;
+    return errret;
   gsub = otf->gsub;
 
   LangSys = get_langsys (&gsub->ScriptList, script, language);
   if (! LangSys)
-    return -1;
+    return errret;
 
   feature_index = alloca (sizeof (int) * gsub->FeatureList.FeatureCount);
   if (! feature_index)
@@ -737,8 +877,12 @@ OTF_drive_gsub (OTF *otf, OTF_GlyphString *gstring,
          int gidx = 0;
 
          while (gidx < gstring->used)
-           gidx = lookup_gsub (&gsub->LookupList, feature->LookupListIndex[j],
-                               gstring, gidx);
+           {
+             gidx = lookup_gsub (&gsub->LookupList,
+                                 feature->LookupListIndex[j], gstring, gidx);
+             if (gidx < 0)
+               return errret;
+           }
        }
     }
 
@@ -759,12 +903,12 @@ OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
 
   if (! otf->gpos
       && OTF_get_table (otf, "GPOS") < 0)
-    return -1;
+    return errret;
   gpos = otf->gpos;
 
   LangSys = get_langsys (&gpos->ScriptList, script, language);
   if (! LangSys)
-    return -1;
+    return errret;
 
   feature_index = alloca (sizeof (int) * gpos->FeatureList.FeatureCount);
   if (! feature_index)
@@ -784,8 +928,12 @@ OTF_drive_gpos (OTF *otf, OTF_GlyphString *gstring,
          int gidx = 0;
 
          while (gidx < gstring->used)
-           gidx = lookup_gpos (&gpos->LookupList, feature->LookupListIndex[j],
-                               gstring, gidx);
+           {
+             gidx = lookup_gpos (&gpos->LookupList,
+                                 feature->LookupListIndex[j], gstring, gidx);
+             if (gidx < 0)
+               return errret;
+           }
        }
     }
 
index aed9623..315d3c9 100644 (file)
@@ -23,7 +23,7 @@ int
 otf__error (int err, char *fmt, void *arg)
 {
   if (! error_message)
-    error_message = (char *) malloc (256);
+    error_message = (char *) malloc (1024);
   sprintf (error_message, "OTF-Error (%s): ", error_string[err]);
   sprintf (error_message + strlen (error_message), fmt, arg);
   OTF_error = err;
index 648429f..d931462 100644 (file)
@@ -1,3 +1,26 @@
+/* otfopen.c -- OpenType font reader.
+
+Copyright (C) 2003
+  by AIST (National Institute of Advanced Industrial Science and Technology)
+  Registration Number H15PRO???
+
+This file is part of the OTF library.
+
+The OTF library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2, or (at
+your option) any later version.
+
+The OTF library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the OTF library; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -5,7 +28,33 @@
 #include "otf.h"
 #include "otferror.h"
 
-/* OTF_Stream
+/***
+    Table of contents (almost parallel to otf.h):
+
+    (0) Stream handler
+
+    (1) Readers for OTF Layout tables and OTF itself
+    (1-1) Basic types and functions
+    (1-2) "head" table
+    (1-3) "name" table
+    (1-4) "cmap" table
+    (1-5) Structures common to GDEF, GSUB, and GPOS
+    (1-6) "GDEF" table
+    (1-7) Structures for ScriptList, FeatureList, and LookupList
+    (1-8) Structures common to GSUB and GPOS
+    (1-9) "GSUB" table
+    (1-10) "GPOS" table
+    (1-11) Structure for OTF
+
+    (2) APIs for reading OTF
+    (2-1) OTF_open()
+    (2-2) OTF_close()
+    (2-3) OTF_get_table()
+
+    (5) APIs miscellaneous
+*/
+\f
+/* (0) Stream handler
 
    Example of typical usage of OTF_Stream.
 
@@ -162,6 +211,9 @@ free_stream (OTF_Stream *stream)
 #define READ_GLYPHID READ_USHORT
 
 \f
+/*** (1) Structures for OTF Layout tables and OTF itself */
+
+/*** (1-1) Basic types and functions */
 
 enum OTF_TableType
   {
@@ -259,134 +311,8 @@ allocate_memory_record (OTF *otf)
       }                                                                        \
   } while (0)
 
-
-\f
-
-static void *read_head_table (OTF *otf, OTF_Stream *stream);
-static void *read_name_table (OTF *otf, OTF_Stream *stream);
-static void *read_cmap_table (OTF *otf, OTF_Stream *stream);
-static void *read_gdef_table (OTF *otf, OTF_Stream *stream);
-static void *read_gsub_table (OTF *otf, OTF_Stream *stream);
-static void *read_gpos_table (OTF *otf, OTF_Stream *stream);
-
-int
-read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table)
-{  
-  int errret = -1;
-
-  READ_FIXED (stream, table->sfnt_version);
-  READ_USHORT (stream, table->numTables);
-  READ_USHORT (stream, table->searchRange);
-  READ_USHORT (stream, table->enterSelector);
-  READ_USHORT (stream, table->rangeShift);
-  return 0;
-}
-
-static OTF_Tag
-read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table)
-{
-  int errret = 0;
-  OTF_Tag tag;
-
-  READ_TAG (stream, tag);
-  table->tag = tag;
-  table->name[0] = tag >> 24;
-  table->name[1] = (tag >> 16) & 0xFF;
-  table->name[0] = (tag >> 8) & 0xFF;
-  table->name[0] = tag >> 8;
-  table->name[0] = '\0';
-  READ_ULONG (stream, table->checkSum);
-  READ_ULONG (stream, table->offset);
-  READ_ULONG (stream, table->length);
-  return tag;
-}
-
-static int
-read_header_part (OTF *otf, FILE *fp)
-{
-  char *errfmt = "otf header%s";
-  int errret = -1;
-  OTF_Tag head_tag, name_tag, cmap_tag, gdef_tag, gsub_tag, gpos_tag;
-  OTF_Stream *stream;
-  int i;
-  OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data;
-
-  internal_data->table_info[OTF_TABLE_TYPE_HEAD].address = (void *) &otf->head;
-  internal_data->table_info[OTF_TABLE_TYPE_HEAD].reader = read_head_table;
-  internal_data->table_info[OTF_TABLE_TYPE_NAME].address = (void *) &otf->name;
-  internal_data->table_info[OTF_TABLE_TYPE_NAME].reader = read_name_table;
-  internal_data->table_info[OTF_TABLE_TYPE_CMAP].address = (void *) &otf->cmap;
-  internal_data->table_info[OTF_TABLE_TYPE_CMAP].reader = read_cmap_table;
-  internal_data->table_info[OTF_TABLE_TYPE_GDEF].address = (void *) &otf->gdef;
-  internal_data->table_info[OTF_TABLE_TYPE_GDEF].reader = read_gdef_table;
-  internal_data->table_info[OTF_TABLE_TYPE_GSUB].address = (void *) &otf->gsub;
-  internal_data->table_info[OTF_TABLE_TYPE_GSUB].reader = read_gsub_table;
-  internal_data->table_info[OTF_TABLE_TYPE_GPOS].address = (void *) &otf->gpos;
-  internal_data->table_info[OTF_TABLE_TYPE_GPOS].reader = read_gpos_table;
-
-  head_tag = OTF_tag ("head");
-  name_tag = OTF_tag ("name");
-  cmap_tag = OTF_tag ("cmap");
-  gdef_tag = OTF_tag ("GDEF");
-  gsub_tag = OTF_tag ("GSUB");
-  gpos_tag = OTF_tag ("GPOS");
-
-  stream = make_stream ();
-  if (! stream)
-    return -1;
-
-  internal_data->header_stream = stream;
-  
-  /* Size of Offset Table is 12 bytes.  */
-  if (setup_stream (stream, fp, 0, 12, "Offset Table") < 0)
-    return -1;
-  if (read_offset_table (otf, stream, &otf->offset_table) < 0)
-    return -1;
-
-  /* Size of each Table Directory is 16 bytes.  */
-  if (setup_stream (stream, fp, 12, 16 * otf->offset_table.numTables,
-                   "Table Directory") < 0)
-    return -1;
-
-  OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables, " (OffsetTable)");
-  for (i = 0; i < otf->offset_table.numTables; i++)
-    {
-      OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i);
-      OTF_TableInfo *table_info = NULL;
-
-      if (! tag)
-       return -1;
-      if (tag == head_tag)
-       table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD;
-      else if (tag == name_tag)
-       table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME;
-      else if (tag == cmap_tag)
-       table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP;
-      else if (tag == gdef_tag)
-       table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF;
-      else if (tag == gsub_tag)
-       table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB;
-      else if (tag == gpos_tag)
-       table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS;
-
-      if (table_info)
-       {
-         table_info->stream = make_stream ();
-         if (setup_stream (table_info->stream, fp,
-                           otf->table_dirs[i].offset,
-                           otf->table_dirs[i].length,
-                           otf->table_dirs[i].name) < 0)
-           return -1;
-       }
-    }
-
-  internal_data->header_stream = NULL;
-  free_stream (stream);
-  return 0;
-}
-
-
 \f
+/*** (1-2) "head" table */
 
 static void *
 read_head_table (OTF *otf, OTF_Stream *stream)
@@ -407,162 +333,207 @@ read_head_table (OTF *otf, OTF_Stream *stream)
 }
 
 \f
+/*** (1-3) "name" table */
 
-static int
-read_script_list (OTF *otf, OTF_Stream *stream, long offset,
-                 OTF_ScriptList *list)
+static char *
+read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec, int bytes)
 {
-  char *errfmt = "Script List%s";
-  int errret = -1;
-  int i, j, k;
+  char *errfmt = "nameID (%d)";
+  void *errret = NULL;
+  OTF_StreamState state;
+  char *str;
+  int i;
+  int c;
 
-  SEEK_STREAM (stream, offset);
-  READ_USHORT (stream, list->ScriptCount);
-  OTF_CALLOC (list->Script, list->ScriptCount, "");
+  SAVE_STREAM (stream, state);
+  SEEK_STREAM (stream, stream->pos + rec->offset);
 
-  for (i = 0; i < list->ScriptCount; i++)
+  if (bytes == 1)
     {
-      READ_TAG (stream, list->Script[i].ScriptTag);
-      READ_OFFSET (stream, list->Script[i].offset);
+      OTF_MALLOC (str, rec->length + 1, (void *) rec->nameID);
+      READ_BYTES (stream, str, rec->length);
+      for (i = 0; i < rec->length; i++)
+       if (str[i] < 0)
+         str[i] = '?';
     }
-  for (i = 0;  i < list->ScriptCount; i++)
+  else if (bytes == 2)
     {
-      OTF_Script *script = list->Script + i;
-      long script_offset = offset + script->offset;
-
-      SEEK_STREAM (stream, script_offset);
-      READ_OFFSET (stream, script->DefaultLangSysOffset);
-      READ_USHORT (stream, script->LangSysCount);
-      OTF_MALLOC (script->LangSysRecord, script->LangSysCount, " (LangSys)");
-      OTF_CALLOC (script->LangSys, script->LangSysCount, " (LangSys)");
-      for (j = 0; j < script->LangSysCount; j++)
-       {
-         READ_TAG (stream, script->LangSysRecord[j].LangSysTag);
-         READ_OFFSET (stream, script->LangSysRecord[j].LangSys);
-       }
-
-      if (script->DefaultLangSysOffset)
+      OTF_MALLOC (str, rec->length / 2 + 1, (void *) rec->nameID);
+      for (i = 0; i < rec->length / 2; i++)
        {
-         OTF_LangSys *langsys = &script->DefaultLangSys;
-
-         SEEK_STREAM (stream, script_offset + script->DefaultLangSysOffset);
-         READ_OFFSET (stream, langsys->LookupOrder);
-         READ_USHORT (stream, langsys->ReqFeatureIndex);
-         READ_USHORT (stream, langsys->FeatureCount);
-         OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount,
-                     " (FeatureIndex)");
-         for (k = 0; k < langsys->FeatureCount; k++)
-           READ_USHORT (stream, langsys->FeatureIndex[k]);
+         READ_USHORT (stream, c);
+         if (c >= 128)
+           c = '?';
+         str[i] = c;
        }
-         
-      for (j = 0; j < script->LangSysCount; j++)
+    }
+  else if (bytes == 4)
+    {
+      OTF_MALLOC (str, rec->length / 4 + 1, (void *) rec->nameID);
+      for (i = 0; i < rec->length / 4; i++)
        {
-         OTF_LangSys *langsys = script->LangSys + j;
-
-         SEEK_STREAM (stream,
-                      script_offset + script->LangSysRecord[j].LangSys);
-         READ_OFFSET (stream, langsys->LookupOrder);
-         READ_USHORT (stream, langsys->ReqFeatureIndex);
-         READ_USHORT (stream, langsys->FeatureCount);
-         OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount,
-                     " (FeatureIndex)");
-         for (k = 0; k < langsys->FeatureCount; k++)
-           READ_USHORT (stream, langsys->FeatureIndex[k]);
+         READ_ULONG (stream, c);
+         if (c >= 128)
+           c = '?';
+         str[i] = c;
        }
     }
-
-  return 0;
+  str[i] = '\0';
+  RESTORE_STREAM (stream, state);
+  return str;
 }
 
-static int
-read_feature_list (OTF *otf, OTF_Stream *stream, long offset,
-                  OTF_FeatureList *list)
+static void *
+read_name_table (OTF *otf, OTF_Stream *stream)
 {
-  char *errfmt = "Feature List%s";
-  int errret = -1;
-  int i, j;
+  char *errfmt = "name%s";
+  void *errret = NULL;
+  OTF_name *name;
+  int i;
 
-  READ_UINT16 (stream, list->FeatureCount);
-  OTF_CALLOC (list->Feature, list->FeatureCount, "");
-  for (i = 0; i < list->FeatureCount; i++)
+  OTF_CALLOC (name, 1, "");
+  READ_USHORT (stream, name->format);
+  READ_USHORT (stream, name->count);
+  READ_USHORT (stream, name->stringOffset);
+  OTF_MALLOC (name->nameRecord, name->count, "");
+  for (i = 0; i < name->count; i++)
     {
-      READ_TAG (stream, list->Feature[i].FeatureTag);
-      READ_OFFSET (stream, list->Feature[i].offset);
+      OTF_NameRecord *rec = name->nameRecord + i;
+
+      READ_USHORT (stream, rec->platformID);
+      READ_USHORT (stream, rec->encodingID);
+      READ_USHORT (stream, rec->languageID);
+      READ_USHORT (stream, rec->nameID);
+      READ_USHORT (stream, rec->length);
+      READ_USHORT (stream, rec->offset);
     }
-  for (i = 0; i < list->FeatureCount; i++)
+  for (i = 0; i < name->count; i++)
     {
-      OTF_Feature *feature = list->Feature + i;
+      OTF_NameRecord *rec = name->nameRecord + i;
+      int nameID = rec->nameID;
 
-      SEEK_STREAM (stream, offset + feature->offset);
-      READ_OFFSET (stream, feature->FeatureParams);
-      READ_UINT16 (stream, feature->LookupCount);
-      OTF_MALLOC (feature->LookupListIndex, feature->LookupCount,
-                 " (LookupListIndex)");
-      for (j = 0; j < feature->LookupCount; j++)
-       READ_UINT16 (stream, feature->LookupListIndex[j]);
+      if (nameID <= OTF_max_nameID
+         && ! name->name[nameID])
+       {
+         if (rec->platformID == 0)
+           name->name[nameID] = read_name (otf, stream, rec,
+                                           rec->encodingID <= 3 ? 2 : 4);
+         else if (rec->platformID == 1
+                  && rec->encodingID == 0)
+           name->name[nameID] = read_name (otf, stream, rec, 1);
+         else if (rec->platformID == 3
+                  && (rec->encodingID == 1 || rec->encodingID == 10))
+           name->name[nameID] = read_name (otf, stream,
+                                           rec, rec->encodingID == 1 ? 2 : 4);
+       }
     }
 
-  return 0;
+  return name;
 }
 
-static int read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream,
-                                     long offset, unsigned type,
-                                     OTF_LookupSubTableGSUB *subtable);
-static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
-                                     long offset, unsigned type,
-                                     OTF_LookupSubTableGPOS *subtable);
+\f
+/*** (1-4) "cmap" table */
 
-static int
-read_lookup_list (OTF *otf, OTF_Stream *stream, long offset,
-                 OTF_LookupList *list, int gsub)
+static void *
+read_cmap_table (OTF *otf, OTF_Stream *stream)
 {
-  char *errfmt = "Lookup List%s";
-  int errret = -1;
-  int i, j;
-
-  SEEK_STREAM (stream, offset);
-  READ_UINT16 (stream, list->LookupCount);
-  OTF_CALLOC (list->Lookup, list->LookupCount, "");
+  char *errfmt = "cmap%s";
+  void *errret = NULL;
+  OTF_cmap *cmap;
+  int i;
 
-  for (i = 0; i < list->LookupCount; i++)
-    READ_OFFSET (stream, list->Lookup[i].offset);
-  for (i = 0; i < list->LookupCount; i++)
+  OTF_CALLOC (cmap, 1, "");
+  READ_USHORT (stream, cmap->version);
+  READ_USHORT (stream, cmap->numTables);
+  OTF_MALLOC (cmap->EncodingRecord, cmap->numTables, "");
+  for (i = 0; i < cmap->numTables; i++)
     {
-      OTF_Lookup *lookup = list->Lookup + i;
+      READ_USHORT (stream, cmap->EncodingRecord[i].platformID);
+      READ_USHORT (stream, cmap->EncodingRecord[i].encodingID);
+      READ_ULONG (stream, cmap->EncodingRecord[i].offset);
+      if (cmap->EncodingRecord[i].platformID == 3
+         && cmap->EncodingRecord[i].encodingID == 1)
+       cmap->Unicode = cmap->EncodingRecord + i;
+    }
+  for (i = 0; i < cmap->numTables; i++)
+    {
+      unsigned format;
 
-      SEEK_STREAM (stream, offset + lookup->offset);
-      READ_UINT16 (stream, lookup->LookupType);
-      READ_UINT16 (stream, lookup->LookupFlag);
-      READ_UINT16 (stream, lookup->SubTableCount);
-      OTF_MALLOC (lookup->SubTableOffset, lookup->SubTableCount,
-                 " (SubTableOffset)");
-      if (gsub)
-       OTF_CALLOC (lookup->SubTable.gsub, lookup->SubTableCount,
-                   " (SubTable)");
+      SEEK_STREAM (stream, cmap->EncodingRecord[i].offset);
+      READ_USHORT (stream, format);
+      cmap->EncodingRecord[i].subtable.format = format;
+      READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length);
+      if (format == 8 || format == 10 || format == 12)
+       {
+         READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length);
+         READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language);
+       }
       else
-       OTF_CALLOC (lookup->SubTable.gpos, lookup->SubTableCount,
-                   " (SubTable)");
-      for (j = 0; j < lookup->SubTableCount; j++)
-       READ_OFFSET (stream, lookup->SubTableOffset[j]);
-      for (j = 0; j < lookup->SubTableCount; j++)
        {
-         long this_offset
-           = offset + lookup->offset + lookup->SubTableOffset[j];
+         READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language);
+       }
+      switch (format)
+       {
+       case 0:
+         {
+           OTF_MALLOC (cmap->EncodingRecord[i].subtable.f.f0, 1,
+                       " (EncodingRecord)");
+           READ_BYTES (stream,
+                       cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray,
+                       256);
+         }
+         break;
 
-         if (gsub
-             ? read_lookup_subtable_gsub (otf, stream, this_offset,
-                                          lookup->LookupType,
-                                          lookup->SubTable.gsub + j) < 0
-             : read_lookup_subtable_gpos (otf, stream, this_offset,
-                                          lookup->LookupType,
-                                          lookup->SubTable.gpos + j) < 0)
-           return errret;
+       case 2:
+         break;
+
+       case 4:
+         {
+           OTF_EncodingSubtable4 *sub4;
+           int segCount;
+           int j;
+           unsigned dummy;
+
+           OTF_MALLOC (sub4, 1, " (EncodingSubtable4)");
+           cmap->EncodingRecord[i].subtable.f.f4 = sub4;
+           READ_USHORT (stream, sub4->segCountX2);
+           segCount = sub4->segCountX2 / 2;
+           READ_USHORT (stream, sub4->searchRange);
+           READ_USHORT (stream, sub4->entrySelector);
+           READ_USHORT (stream, sub4->rangeShift);
+           OTF_MALLOC (sub4->segments, segCount, " (segCount)");
+           for (j = 0; j < segCount; j++)
+             READ_USHORT (stream, sub4->segments[j].endCount);
+           READ_USHORT (stream, dummy);
+           for (j = 0; j < segCount; j++)
+             READ_USHORT (stream, sub4->segments[j].startCount);
+           for (j = 0; j < segCount; j++)
+             READ_SHORT (stream, sub4->segments[j].idDelta);
+           for (j = 0; j < segCount; j++)
+             {
+               unsigned off;
+               unsigned rest = 2 * (segCount - j);
+               
+               READ_USHORT (stream, off);
+               if (off == 0)
+                 sub4->segments[j].idRangeOffset = 0xFFFF;
+               else
+                 sub4->segments[j].idRangeOffset = (off - rest) / 2;
+             }
+           j = (cmap->EncodingRecord[i].subtable.length
+                - (14 + 2 * (segCount * 4 + 1)));
+           sub4->GlyphCount = j / 2;
+           OTF_MALLOC (sub4->glyphIdArray, sub4->GlyphCount, " (GlyphCount)");
+           for (j = 0; j < sub4->GlyphCount; j++)
+             READ_USHORT (stream, sub4->glyphIdArray[j]);
+         }
        }
     }
-
-  return 0;
+  return cmap;
 }
 
+\f
+/*** (1-5) Structures common to GDEF, GSUB, and GPOS */
 
 /* Read Glyph-IDs from STREAM.  Allocate memory for IDS, and store the
    Glyph-IDs there.  If COUNT is negative, read the number of
@@ -789,76 +760,367 @@ read_device_table (OTF *otf, OTF_Stream *stream, long offset,
   return 0;
 }
 
-static unsigned
-read_lookup_record_list (OTF *otf, OTF_Stream *stream,
-                        OTF_LookupRecord **record, int count)
+\f
+/*** (1-6) "GDEF" table */
+
+static int
+read_attach_list (OTF *otf, OTF_Stream *stream, long offset,
+                 OTF_AttachList *list)
 {
-  char *errfmt = "LookupRecord%s";
-  unsigned errret = 0;
-  int i;
+  char *errfmt = "AttachList%s";
+  int errret = -1;
+  int i, j;
 
-  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++)
+  if (read_coverage (otf, stream, offset, &list->Coverage) < 0)
+    return -1;
+  READ_UINT16 (stream, list->GlyphCount);
+  OTF_MALLOC (list->AttachPoint, list->GlyphCount, "");
+  for (i = 0; i < list->GlyphCount; i++)
+    READ_OFFSET (stream, list->AttachPoint[i].offset);
+  for (i = 0; i < list->GlyphCount; i++)
     {
-      READ_UINT16 (stream, (*record)[i].SequenceIndex);
-      READ_UINT16 (stream, (*record)[i].LookupListIndex);
+      int count;
+
+      SEEK_STREAM (stream, offset + list->AttachPoint[i].offset);
+      READ_UINT16 (stream, count);
+      list->AttachPoint[i].PointCount = count;
+      OTF_MALLOC (list->AttachPoint[i].PointIndex, count, " (PointIndex)");
+      for (j = 0; j < count; j++)
+       READ_UINT16 (stream, list->AttachPoint[i].PointIndex[j]);
     }
-  return count;
+  return 0;
 }
 
-static unsigned
-read_rule_list (OTF *otf, OTF_Stream *stream, long offset, OTF_Rule **rule)
+static int
+read_caret_value (OTF *otf, OTF_Stream *stream, long offset,
+                 OTF_CaretValue *caret)
 {
-  char *errfmt = "List of Rule%s";
-  unsigned errret = 0;
-  OTF_StreamState state;
-  unsigned count;
-  int i;
+  char *errfmt = "CaretValue%s";
+  int errret = -1;
 
-  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)");
-    }
-  SAVE_STREAM (stream, state);
-  for (i = 0; i < count; i++)
+  SEEK_STREAM (stream, offset + caret->offset);
+  READ_UINT16 (stream, caret->CaretValueFormat);
+  if (caret->CaretValueFormat == 1)
+    READ_INT16 (stream, caret->f.f1.Coordinate);
+  else if (caret->CaretValueFormat == 2)
+    READ_UINT16 (stream, caret->f.f2.CaretValuePoint);
+  else if (caret->CaretValueFormat == 3)
     {
-      SEEK_STREAM (stream, offset + (*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;
+      READ_INT16 (stream, caret->f.f3.Coordinate);
+      if (read_device_table (otf, stream, offset + caret->offset,
+                            &caret->f.f3.DeviceTable) < 0)
+       return -1;
     }
-  RESTORE_STREAM (stream, state);
-  return count;
+  else
+    OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)");
+  return 0;
 }
 
-
-static unsigned
-read_rule_set_list (OTF *otf, OTF_Stream *stream, long offset,
-                   OTF_RuleSet **set)
+static int
+read_lig_caret_list (OTF *otf, OTF_Stream *stream, long offset,
+                    OTF_LigCaretList *list)
 {
-  char *errfmt = "List of RuleSet%s";
-  unsigned errret = 0;
-  OTF_StreamState state;
-  unsigned count;
-  int i;
-
+  char *errfmt = "LigCaretList%s";
+  int errret = -1;
+  int i, j;
+
+  if (read_coverage (otf, stream, offset, &list->Coverage) < 0)
+    return -1;
+  READ_UINT16 (stream, list->LigGlyphCount);
+  OTF_MALLOC (list->LigGlyph, list->LigGlyphCount, "");
+  for (i = 0; i < list->LigGlyphCount; i++)
+    READ_OFFSET (stream, list->LigGlyph[i].offset);
+  for (i = 0; i < list->LigGlyphCount; i++)
+    {
+      int count;
+
+      SEEK_STREAM (stream, offset + list->LigGlyph[i].offset);
+      READ_UINT16 (stream, count);
+      list->LigGlyph[i].CaretCount = count;
+      OTF_MALLOC (list->LigGlyph[i].CaretValue, count, " (CaretValue)");
+      for (j = 0; j < count; j++)
+       READ_OFFSET (stream, list->LigGlyph[i].CaretValue[j].offset);
+      for (j = 0; j < count; j++)
+       if (read_caret_value (otf, stream, offset + list->LigGlyph[i].offset,
+                             &list->LigGlyph[i].CaretValue[j]) < 0)
+         return -1;
+    }
+  return 0;
+}
+
+static int
+read_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header)
+{
+  int errret = -1;
+
+  READ_FIXED (stream, header->Version);
+  READ_OFFSET (stream, header->GlyphClassDef);
+  READ_OFFSET (stream, header->AttachList);
+  READ_OFFSET (stream, header->LigCaretList);
+  READ_OFFSET (stream, header->MarkAttachClassDef);
+  return 0;
+}
+
+static void *
+read_gdef_table (OTF *otf, OTF_Stream *stream)
+{
+  char *errfmt = "GDEF%s";
+  void *errret = NULL;
+  OTF_GDEF *gdef;
+
+  OTF_CALLOC (gdef, 1, "");
+  read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header);
+  if (gdef->header.GlyphClassDef)
+    {
+      gdef->glyph_class_def.offset = gdef->header.GlyphClassDef;
+      read_class_def_without_offset (otf, stream, &gdef->glyph_class_def);
+    }
+  if (gdef->header.AttachList)
+    read_attach_list (otf, stream, gdef->header.AttachList,
+                     &gdef->attach_list);
+  if (gdef->header.LigCaretList)
+    read_lig_caret_list (otf, stream, gdef->header.LigCaretList,
+                        &gdef->lig_caret_list);
+  if (gdef->header.MarkAttachClassDef)
+    {
+      gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef;
+      read_class_def_without_offset (otf, stream, &gdef->mark_attach_class_def);
+    }
+
+  return gdef;
+}
+
+\f
+/*** (1-7) Structures for ScriptList, FeatureList, and LookupList */
+
+static int
+read_script_list (OTF *otf, OTF_Stream *stream, long offset,
+                 OTF_ScriptList *list)
+{
+  char *errfmt = "Script List%s";
+  int errret = -1;
+  int i, j, k;
+
+  SEEK_STREAM (stream, offset);
+  READ_USHORT (stream, list->ScriptCount);
+  OTF_CALLOC (list->Script, list->ScriptCount, "");
+
+  for (i = 0; i < list->ScriptCount; i++)
+    {
+      READ_TAG (stream, list->Script[i].ScriptTag);
+      READ_OFFSET (stream, list->Script[i].offset);
+    }
+  for (i = 0;  i < list->ScriptCount; i++)
+    {
+      OTF_Script *script = list->Script + i;
+      long script_offset = offset + script->offset;
+
+      SEEK_STREAM (stream, script_offset);
+      READ_OFFSET (stream, script->DefaultLangSysOffset);
+      READ_USHORT (stream, script->LangSysCount);
+      OTF_MALLOC (script->LangSysRecord, script->LangSysCount, " (LangSys)");
+      OTF_CALLOC (script->LangSys, script->LangSysCount, " (LangSys)");
+      for (j = 0; j < script->LangSysCount; j++)
+       {
+         READ_TAG (stream, script->LangSysRecord[j].LangSysTag);
+         READ_OFFSET (stream, script->LangSysRecord[j].LangSys);
+       }
+
+      if (script->DefaultLangSysOffset)
+       {
+         OTF_LangSys *langsys = &script->DefaultLangSys;
+
+         SEEK_STREAM (stream, script_offset + script->DefaultLangSysOffset);
+         READ_OFFSET (stream, langsys->LookupOrder);
+         READ_USHORT (stream, langsys->ReqFeatureIndex);
+         READ_USHORT (stream, langsys->FeatureCount);
+         OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount,
+                     " (FeatureIndex)");
+         for (k = 0; k < langsys->FeatureCount; k++)
+           READ_USHORT (stream, langsys->FeatureIndex[k]);
+       }
+         
+      for (j = 0; j < script->LangSysCount; j++)
+       {
+         OTF_LangSys *langsys = script->LangSys + j;
+
+         SEEK_STREAM (stream,
+                      script_offset + script->LangSysRecord[j].LangSys);
+         READ_OFFSET (stream, langsys->LookupOrder);
+         READ_USHORT (stream, langsys->ReqFeatureIndex);
+         READ_USHORT (stream, langsys->FeatureCount);
+         OTF_MALLOC (langsys->FeatureIndex, langsys->FeatureCount,
+                     " (FeatureIndex)");
+         for (k = 0; k < langsys->FeatureCount; k++)
+           READ_USHORT (stream, langsys->FeatureIndex[k]);
+       }
+    }
+
+  return 0;
+}
+
+static int
+read_feature_list (OTF *otf, OTF_Stream *stream, long offset,
+                  OTF_FeatureList *list)
+{
+  char *errfmt = "Feature List%s";
+  int errret = -1;
+  int i, j;
+
+  READ_UINT16 (stream, list->FeatureCount);
+  OTF_CALLOC (list->Feature, list->FeatureCount, "");
+  for (i = 0; i < list->FeatureCount; i++)
+    {
+      READ_TAG (stream, list->Feature[i].FeatureTag);
+      READ_OFFSET (stream, list->Feature[i].offset);
+    }
+  for (i = 0; i < list->FeatureCount; i++)
+    {
+      OTF_Feature *feature = list->Feature + i;
+
+      SEEK_STREAM (stream, offset + feature->offset);
+      READ_OFFSET (stream, feature->FeatureParams);
+      READ_UINT16 (stream, feature->LookupCount);
+      OTF_MALLOC (feature->LookupListIndex, feature->LookupCount,
+                 " (LookupListIndex)");
+      for (j = 0; j < feature->LookupCount; j++)
+       READ_UINT16 (stream, feature->LookupListIndex[j]);
+    }
+
+  return 0;
+}
+
+static int read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream,
+                                     long offset, unsigned type,
+                                     OTF_LookupSubTableGSUB *subtable);
+static int read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
+                                     long offset, unsigned type,
+                                     OTF_LookupSubTableGPOS *subtable);
+
+static int
+read_lookup_list (OTF *otf, OTF_Stream *stream, long offset,
+                 OTF_LookupList *list, int gsubp)
+{
+  char *errfmt = "Lookup List%s";
+  int errret = -1;
+  int i, j;
+
+  SEEK_STREAM (stream, offset);
+  READ_UINT16 (stream, list->LookupCount);
+  OTF_CALLOC (list->Lookup, list->LookupCount, "");
+
+  for (i = 0; i < list->LookupCount; i++)
+    READ_OFFSET (stream, list->Lookup[i].offset);
+  for (i = 0; i < list->LookupCount; i++)
+    {
+      OTF_Lookup *lookup = list->Lookup + i;
+
+      SEEK_STREAM (stream, offset + lookup->offset);
+      READ_UINT16 (stream, lookup->LookupType);
+      READ_UINT16 (stream, lookup->LookupFlag);
+      READ_UINT16 (stream, lookup->SubTableCount);
+      OTF_MALLOC (lookup->SubTableOffset, lookup->SubTableCount,
+                 " (SubTableOffset)");
+      if (gsubp)
+       OTF_CALLOC (lookup->SubTable.gsub, lookup->SubTableCount,
+                   " (SubTable)");
+      else
+       OTF_CALLOC (lookup->SubTable.gpos, lookup->SubTableCount,
+                   " (SubTable)");
+      for (j = 0; j < lookup->SubTableCount; j++)
+       READ_OFFSET (stream, lookup->SubTableOffset[j]);
+      for (j = 0; j < lookup->SubTableCount; j++)
+       {
+         long this_offset
+           = offset + lookup->offset + lookup->SubTableOffset[j];
+
+         if (gsubp
+             ? read_lookup_subtable_gsub (otf, stream, this_offset,
+                                          lookup->LookupType,
+                                          lookup->SubTable.gsub + j) < 0
+             : read_lookup_subtable_gpos (otf, stream, this_offset,
+                                          lookup->LookupType,
+                                          lookup->SubTable.gpos + j) < 0)
+           return errret;
+       }
+    }
+
+  return 0;
+}
+
+\f
+/*** (1-8) Structures common to GSUB and GPOS */
+
+static unsigned
+read_lookup_record_list (OTF *otf, OTF_Stream *stream,
+                        OTF_LookupRecord **record, int count)
+{
+  char *errfmt = "LookupRecord%s";
+  unsigned errret = 0;
+  int i;
+
+  if (count < 0)
+    READ_UINT16 (stream, count);
+  if (! count)
+    OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
+  OTF_MALLOC (*record, count, "");
+  for (i = 0; i < count; i++)
+    {
+      READ_UINT16 (stream, (*record)[i].SequenceIndex);
+      READ_UINT16 (stream, (*record)[i].LookupListIndex);
+    }
+  return count;
+}
+
+static unsigned
+read_rule_list (OTF *otf, OTF_Stream *stream, long offset, OTF_Rule **rule)
+{
+  char *errfmt = "List of Rule%s";
+  unsigned errret = 0;
+  OTF_StreamState state;
+  unsigned count;
+  int i;
+
+  READ_UINT16 (stream, count);
+  if (! count)
+    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)");
+    }
+  SAVE_STREAM (stream, state);
+  for (i = 0; i < count; i++)
+    {
+      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 unsigned
+read_rule_set_list (OTF *otf, OTF_Stream *stream, long offset,
+                   OTF_RuleSet **set)
+{
+  char *errfmt = "List of RuleSet%s";
+  unsigned errret = 0;
+  OTF_StreamState state;
+  unsigned count;
+  int i;
+
   READ_UINT16 (stream, count);
   if (! count)
     OTF_ERROR (OTF_ERROR_TABLE, " (zero count)");
@@ -1069,559 +1331,305 @@ read_chain_class_rule_list (OTF *otf, OTF_Stream *stream, long offset,
 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;
-}
-
-\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 + (*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;
+{
+  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 (*altset, count, "");
+  OTF_MALLOC (*set, count, "");
   for (i = 0; i < count; i++)
-    READ_OFFSET (stream, (*altset)[i].offset);
+    /* Offset may be zero.  */
+    READ_OFFSET (stream, (*set)[i].offset);
+  SAVE_STREAM (stream, state);
   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;
-    }
+    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_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset,
-                          unsigned type, OTF_LookupSubTableGSUB *subtable)
+static int
+read_context1 (OTF *otf, OTF_Stream *stream, long offset,
+              OTF_Coverage *coverage,OTF_Context1 *context1)
 {
-  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:
-      if (subtable->Format == 1)
-       {
-         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
-           return -1;
-         READ_INT16 (stream, subtable->u.single1.DeltaGlyphID);
-       }
-      else if (subtable->Format == 2)
-       {
-         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
-           return -1;
-         subtable->u.single2.GlyphCount
-           = read_glyph_ids (otf, stream, &subtable->u.single2.Substitute,
-                             0, -1);
-         if (! subtable->u.single2.GlyphCount)
-           return -1;
-       }
-      else
-       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
-      break;
-
-    case 2:
-      if (subtable->Format == 1)
-       {
-         read_coverage (otf, stream, offset, &subtable->Coverage);
-         subtable->u.multiple1.SequenceCount
-           = read_sequence (otf, stream, offset,
-                            &subtable->u.multiple1.Sequence);
-       }
-      else
-       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
-      break;
-      
-    case 3:
-      if (subtable->Format == 1)
-       {
-         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
-           return -1;
-         subtable->u.alternate1.AlternateSetCount
-           = read_alternate_set_list (otf, stream, offset,
-                                      &subtable->u.alternate1.AlternateSet);
-         if (! subtable->u.alternate1.AlternateSetCount)
-           return -1;
-       }
-      else
-       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
-      break;
-
-    case 4:
-      if (subtable->Format == 1)
-       {
-         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;
-       }
-      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);
-         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, &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)
-       {
-         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;
-         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->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)");
-    }
+  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;
 }
 
-\f
-/* GPOS */
+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_value_record (OTF *otf, OTF_Stream *stream, long offset,
-                  enum OTF_ValueFormat bit, OTF_ValueRecord *value_record)
+read_context3 (OTF *otf, OTF_Stream *stream, long offset,
+              OTF_Coverage *coverage,OTF_Context3 *context3)
 {
+  char *errfmt = "Context1%s";
   int errret = -1;
-  OTF_StreamState state;
-  int size, i;
-
-  if (! bit)
-    return 0;
-  for (i = 0, size = 0; i < 8; i++)
-    if (bit & (1 << i))
-      size += 2;
 
-  if (bit & OTF_XPlacement)
-    READ_INT16 (stream, value_record->XPlacement);
-  if (bit & OTF_XPlacement)
-    READ_INT16 (stream, value_record->YPlacement);
-  if (bit & OTF_XAdvance)
-    READ_INT16 (stream, value_record->XAdvance);
-  if (bit & OTF_YAdvance)
-    READ_INT16 (stream, value_record->YAdvance);
-  if (bit & OTF_XPlaDevice)
-    READ_OFFSET (stream, value_record->XPlaDevice.offset);
-  if (bit & OTF_YPlaDevice)
-    READ_OFFSET (stream, value_record->YPlaDevice.offset);
-  if (bit & OTF_XAdvDevice)
-    READ_OFFSET (stream, value_record->XAdvDevice.offset);
-  if (bit & OTF_YAdvDevice)
-    READ_OFFSET (stream, value_record->YAdvDevice.offset);
-  SAVE_STREAM (stream, state);
-  if (value_record->XPlaDevice.offset)
-    {
-      if (read_device_table (otf, stream, offset, &value_record->XPlaDevice) < 0)
-       return -1;
-    }
-  if (value_record->YPlaDevice.offset)
-    {
-      if (read_device_table (otf, stream, offset, &value_record->YPlaDevice) < 0)
-       return -1;
-    }
-  if (value_record->XAdvDevice.offset)
-    {
-      if (read_device_table (otf, stream, offset, &value_record->XAdvDevice) < 0)
-       return -1;
-    }
-  if (value_record->YAdvDevice.offset)
-    {
-      if (read_device_table (otf, stream, offset, &value_record->YAdvDevice) < 0)
-       return -1;
-    }
-  RESTORE_STREAM (stream, state);
+  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_anchor (OTF *otf, OTF_Stream *stream, long offset, OTF_Anchor *anchor)
+read_chain_context2 (OTF *otf, OTF_Stream *stream, long offset,
+                    OTF_Coverage *coverage, OTF_ChainContext2 *chain_context2)
 {
-  char *errfmt = "Anchor%s";
-  int errret = -1;
+  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;
+}
 
-  SEEK_STREAM (stream, offset + anchor->offset);
-  READ_UINT16 (stream, anchor->AnchorFormat);
-  READ_INT16 (stream, anchor->XCoordinate);
-  READ_INT16 (stream, anchor->YCoordinate);
-  if (anchor->AnchorFormat == 1)
-    ;
-  else if (anchor->AnchorFormat == 2)
-    {
-      READ_UINT16 (stream, anchor->f.f1.AnchorPoint);
-    }
-  else if (anchor->AnchorFormat == 3)
-    {
-      READ_OFFSET (stream, anchor->f.f2.XDeviceTable.offset);
-      READ_OFFSET (stream, anchor->f.f2.YDeviceTable.offset);
-      if (anchor->f.f2.XDeviceTable.offset)
-       {
-         if (read_device_table (otf, stream, offset + anchor->offset,
-                                &anchor->f.f2.XDeviceTable) < 0)
-           return -1;
-       }
-      if (anchor->f.f2.YDeviceTable.offset)
-       {
-         if (read_device_table (otf, stream, offset + anchor->offset,
-                                &anchor->f.f2.YDeviceTable) < 0)
-           return -1;
-       }
-    }
-  else
-    OTF_ERROR (OTF_ERROR_TABLE, " (invalid format)");
+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 int
-read_mark_array (OTF *otf, OTF_Stream *stream, long offset,
-                OTF_MarkArray *array)
+static void *
+read_gsub_gpos_table (OTF *otf, OTF_Stream *stream, int gsubp)
 {
-  char *errfmt = "MarkArray%s";
-  int errret = -1;
-  OTF_StreamState state;
+  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_OFFSET (stream, array->offset);
-  SAVE_STREAM (stream, state);
-  SEEK_STREAM (stream, offset + array->offset);
-  READ_UINT16 (stream, array->MarkCount);
-  OTF_MALLOC (array->MarkRecord, array->MarkCount, "");
-  for (i = 0; i < array->MarkCount; 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++)
     {
-      READ_UINT16 (stream, array->MarkRecord[i].Class);
-      READ_OFFSET (stream, array->MarkRecord[i].MarkAnchor.offset);
+      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;
     }
-  for (i = 0; i < array->MarkCount; i++)
-    if (read_anchor (otf, stream, offset + array->offset,
-                    &array->MarkRecord[i].MarkAnchor) < 0)
-      return -1;;
-  RESTORE_STREAM (stream, state);
-  return 0;
+  return count;
 }
 
 static int
-read_anchor_array (OTF *otf, OTF_Stream *stream, long offset,
-                  unsigned ClassCount, OTF_AnchorArray *array)
+read_ligature (OTF *otf, OTF_Stream *stream, long offset,
+              OTF_Ligature **ligature)
 {
-  char *errfmt = "AnchorArray%s";
+  char *errfmt = "Ligature%s";
   int errret = -1;
-  OTF_StreamState state;
-  int i, j;
-  
-  READ_OFFSET (stream, array->offset);
-  SAVE_STREAM (stream, state);
-  SEEK_STREAM (stream, offset + array->offset);
-  READ_UINT16 (stream, array->Count);
-  OTF_MALLOC (array->AnchorRecord, array->Count, "");
-  for (i = 0; i < array->Count; i++)
+  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++)
     {
-      OTF_MALLOC (array->AnchorRecord[i].Anchor, ClassCount,
-                 " (AnchorRecord)");
-      for (j = 0; j < ClassCount; j++)
-       READ_OFFSET (stream, array->AnchorRecord[i].Anchor[j].offset);
-    }
-  for (i = 0; i < array->Count; i++)
-    for (j = 0; j < ClassCount; j++)
-      if (read_anchor (otf, stream, offset + array->offset,
-                      &array->AnchorRecord[i].Anchor[j]) < 0)
+      SEEK_STREAM (stream, offset + (*ligature)[i].offset);
+      READ_GLYPHID (stream, (*ligature)[i].LigGlyph);
+      (*ligature)[i].CompCount
+       = read_glyph_ids (otf, stream, &(*ligature)[i].Component, -1, -1);
+      if (! (*ligature)[i].CompCount)
        return -1;
-  RESTORE_STREAM (stream, state);
-  return 0;
+    }
+  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;
 
-static OTF_Class1Record *
-read_class1_record_list (OTF *otf, OTF_Stream *stream, long offset,
-                        unsigned num1, enum OTF_ValueFormat bit1,
-                        unsigned num2, enum OTF_ValueFormat bit2)
+  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 = "Class1Record%s";
-  void *errret = NULL;
-  OTF_Class1Record *rec;
-  int i, j;
+  char *errfmt = "AlternateSet%s";
+  int errret = -1;
+  unsigned count;
+  int i;
 
-  OTF_MALLOC (rec, num1, "");
-  for (i = 0; i < num1; 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++)
     {
-      OTF_CALLOC (rec[i].Class2Record, num2, " (Class2Record)");
-      for (j = 0; j < num2; j++)
-       {
-         if (read_value_record (otf, stream, offset,
-                                bit1, &rec[i].Class2Record[j].Value1) < 0
-             || read_value_record (otf, stream, offset,
-                                   bit2, &rec[i].Class2Record[j].Value2) < 0)
-           return NULL;
-       }
+      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 rec;
+  return count;
 }
 
 static int 
-read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
-                          long offset, unsigned type,
-                          OTF_LookupSubTableGPOS *subtable)
+read_lookup_subtable_gsub (OTF *otf, OTF_Stream *stream, long offset,
+                          unsigned type, OTF_LookupSubTableGSUB *subtable)
 {
   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);
+  sprintf (errfmt, "GSUB Lookup %d-%d%%s", type, subtable->Format);
   switch (type)
     {
     case 1:
       if (subtable->Format == 1)
        {
-         READ_UINT16 (stream, subtable->u.single1.ValueFormat);
-         read_value_record (otf, stream, offset,
-                            subtable->u.single1.ValueFormat,
-                            &subtable->u.single1.Value);
+         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
+           return -1;
+         READ_INT16 (stream, subtable->u.single1.DeltaGlyphID);
        }
       else if (subtable->Format == 2)
        {
-         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);
+         if (read_coverage (otf, stream, offset, &subtable->Coverage) < 0)
+           return -1;
+         subtable->u.single2.GlyphCount
+           = read_glyph_ids (otf, stream, &subtable->u.single2.Substitute,
+                             0, -1);
+         if (! subtable->u.single2.GlyphCount)
+           return -1;
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
@@ -1630,163 +1638,94 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
     case 2:
       if (subtable->Format == 1)
        {
-         OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
-       }
-      else if (subtable->Format == 2)
-       {
-         SEEK_STREAM (stream, offset + 2);
          read_coverage (otf, stream, offset, &subtable->Coverage);
-         READ_UINT16 (stream, subtable->u.pair2.ValueFormat1);
-         READ_UINT16 (stream, subtable->u.pair2.ValueFormat2);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.pair2.ClassDef1);
-         read_class_def (otf, stream, offset,
-                         &subtable->u.pair2.ClassDef2);
-         READ_UINT16 (stream, subtable->u.pair2.Class1Count);
-         READ_UINT16 (stream, subtable->u.pair2.Class2Count);
-         subtable->u.pair2.Class1Record
-           = read_class1_record_list (otf, stream, offset,
-                                      subtable->u.pair2.Class1Count,
-                                      subtable->u.pair2.ValueFormat1,
-                                      subtable->u.pair2.Class2Count,
-                                      subtable->u.pair2.ValueFormat2);
+         subtable->u.multiple1.SequenceCount
+           = read_sequence (otf, stream, offset,
+                            &subtable->u.multiple1.Sequence);
        }
       else
        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)
        {
-         read_coverage (otf, stream, offset, &subtable->Coverage);
-         read_coverage (otf, stream, offset,
-                        &subtable->u.mark_base1.BaseCoverage);
-         READ_UINT16 (stream, subtable->u.mark_base1.ClassCount);
-         read_mark_array (otf, stream, offset,
-                          &subtable->u.mark_base1.MarkArray);
-         read_anchor_array (otf, stream, offset,
-                            subtable->u.mark_base1.ClassCount,
-                            &subtable->u.mark_base1.BaseArray);
+         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 5:
-      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
-      break;
-
-    case 6:
+    case 4:
       if (subtable->Format == 1)
-       {
-         read_coverage (otf, stream, offset, &subtable->Coverage);
-         read_coverage (otf, stream, offset,
-                        &subtable->u.mark_mark1.Mark2Coverage);
-         READ_UINT16 (stream, subtable->u.mark_base1.ClassCount);
-         read_mark_array (otf, stream, offset,
-                          &subtable->u.mark_mark1.Mark1Array);
-         read_anchor_array (otf, stream, offset,
-                            subtable->u.mark_mark1.ClassCount,
-                            &subtable->u.mark_mark1.Mark2Array);
+       {
+         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;
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
 
-    case 7:
+    case 5:
       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);
+         if (read_context1 (otf, stream, offset, &subtable->Coverage,
+                            &subtable->u.context1) < 0)
+           return errret;
        }
       else if (subtable->Format == 2)
        {
-         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);
-         
+         if (read_context2 (otf, stream, offset, &subtable->Coverage,
+                            &subtable->u.context2) < 0)
+           return errret;
        }
       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;
+         if (read_context3 (otf, stream, offset, &subtable->Coverage,
+                            &subtable->u.context3) < 0)
+           return errret;
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
-
-    case 8:
+      
+    case 6:
       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);
+         if (read_chain_context1 (otf, stream, offset, &subtable->Coverage,
+                                  &subtable->u.chain_context1) < 0)
+           return errret;
        }
       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);
+         if (read_chain_context2 (otf, stream, offset, &subtable->Coverage,
+                                  &subtable->u.chain_context2) < 0)
+           return errret;
        }
       else if (subtable->Format == 3)
        {
-         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);
+         if (read_chain_context3 (otf, stream, offset, &subtable->Coverage,
+                                  &subtable->u.chain_context3) < 0)
+           return errret;
        }
       else
        OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
       break;
-
-    case 9:
-      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+      
+    case 7:
+    case 8:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");      
       break;
 
     default:
@@ -1795,416 +1734,517 @@ read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
   return 0;
 }
 
-
 static void *
-read_gpos_table (OTF *otf, OTF_Stream *stream)
-{
-  char *errfmt = "GPOS%s";
-  void *errret = NULL;
-  OTF_GPOS *gpos;
-
-  OTF_CALLOC (gpos, 1, "");
-  READ_FIXED (stream, gpos->Version);
-  READ_OFFSET (stream, gpos->ScriptList.offset);
-  READ_OFFSET (stream, gpos->FeatureList.offset);
-  READ_OFFSET (stream, gpos->LookupList.offset);
-
-  if (read_script_list (otf, stream, gpos->ScriptList.offset,
-                          &gpos->ScriptList) < 0
-      || read_feature_list (otf, stream, gpos->FeatureList.offset,
-                           &gpos->FeatureList) < 0
-      || read_lookup_list (otf, stream, gpos->LookupList.offset,
-                          &gpos->LookupList, 0) < 0)
-    return NULL;
-  return gpos;
-}
-
-\f
-#if 0
-/* BASE */
-
-static OTF_BASE *
-read_base_table (OTF_Stream *stream, long offset)
+read_gsub_table (OTF *otf, OTF_Stream *stream)
 {
-  OTF_BASE *base;
-
-  OTF_MALLOC (base, 1);
-
-  return base;
+  return read_gsub_gpos_table (otf, stream, 1);
 }
 
 \f
-/* JSTF */
-
-static OTF_JSTF *
-read_jstf_table (OTF_Stream *stream, long offset)
-{
-  OTF_JSTF *jstf;
-
-  OTF_MALLOC (jstf, 1);
+/* (1-10) "GPOS" table */
 
-  return jstf;
-}
-#endif /* 0 */
-\f
-/* GDEF */
 static int
-read_attach_list (OTF *otf, OTF_Stream *stream, long offset,
-                 OTF_AttachList *list)
+read_value_record (OTF *otf, OTF_Stream *stream, long offset,
+                  enum OTF_ValueFormat bit, OTF_ValueRecord *value_record)
 {
-  char *errfmt = "AttachList%s";
   int errret = -1;
-  int i, j;
+  OTF_StreamState state;
+  int size, i;
 
-  if (read_coverage (otf, stream, offset, &list->Coverage) < 0)
-    return -1;
-  READ_UINT16 (stream, list->GlyphCount);
-  OTF_MALLOC (list->AttachPoint, list->GlyphCount, "");
-  for (i = 0; i < list->GlyphCount; i++)
-    READ_OFFSET (stream, list->AttachPoint[i].offset);
-  for (i = 0; i < list->GlyphCount; i++)
-    {
-      int count;
+  if (! bit)
+    return 0;
+  for (i = 0, size = 0; i < 8; i++)
+    if (bit & (1 << i))
+      size += 2;
 
-      SEEK_STREAM (stream, offset + list->AttachPoint[i].offset);
-      READ_UINT16 (stream, count);
-      list->AttachPoint[i].PointCount = count;
-      OTF_MALLOC (list->AttachPoint[i].PointIndex, count, " (PointIndex)");
-      for (j = 0; j < count; j++)
-       READ_UINT16 (stream, list->AttachPoint[i].PointIndex[j]);
+  if (bit & OTF_XPlacement)
+    READ_INT16 (stream, value_record->XPlacement);
+  if (bit & OTF_XPlacement)
+    READ_INT16 (stream, value_record->YPlacement);
+  if (bit & OTF_XAdvance)
+    READ_INT16 (stream, value_record->XAdvance);
+  if (bit & OTF_YAdvance)
+    READ_INT16 (stream, value_record->YAdvance);
+  if (bit & OTF_XPlaDevice)
+    READ_OFFSET (stream, value_record->XPlaDevice.offset);
+  if (bit & OTF_YPlaDevice)
+    READ_OFFSET (stream, value_record->YPlaDevice.offset);
+  if (bit & OTF_XAdvDevice)
+    READ_OFFSET (stream, value_record->XAdvDevice.offset);
+  if (bit & OTF_YAdvDevice)
+    READ_OFFSET (stream, value_record->YAdvDevice.offset);
+  SAVE_STREAM (stream, state);
+  if (value_record->XPlaDevice.offset)
+    {
+      if (read_device_table (otf, stream, offset, &value_record->XPlaDevice) < 0)
+       return -1;
+    }
+  if (value_record->YPlaDevice.offset)
+    {
+      if (read_device_table (otf, stream, offset, &value_record->YPlaDevice) < 0)
+       return -1;
+    }
+  if (value_record->XAdvDevice.offset)
+    {
+      if (read_device_table (otf, stream, offset, &value_record->XAdvDevice) < 0)
+       return -1;
+    }
+  if (value_record->YAdvDevice.offset)
+    {
+      if (read_device_table (otf, stream, offset, &value_record->YAdvDevice) < 0)
+       return -1;
     }
+  RESTORE_STREAM (stream, state);
   return 0;
 }
 
+
 static int
-read_caret_value (OTF *otf, OTF_Stream *stream, long offset,
-                 OTF_CaretValue *caret)
+read_anchor (OTF *otf, OTF_Stream *stream, long offset, OTF_Anchor *anchor)
 {
-  char *errfmt = "CaretValue%s";
+  char *errfmt = "Anchor%s";
   int errret = -1;
 
-  SEEK_STREAM (stream, offset + caret->offset);
-  READ_UINT16 (stream, caret->CaretValueFormat);
-  if (caret->CaretValueFormat == 1)
-    READ_INT16 (stream, caret->f.f1.Coordinate);
-  else if (caret->CaretValueFormat == 2)
-    READ_UINT16 (stream, caret->f.f2.CaretValuePoint);
-  else if (caret->CaretValueFormat == 3)
+  SEEK_STREAM (stream, offset + anchor->offset);
+  READ_UINT16 (stream, anchor->AnchorFormat);
+  READ_INT16 (stream, anchor->XCoordinate);
+  READ_INT16 (stream, anchor->YCoordinate);
+  if (anchor->AnchorFormat == 1)
+    ;
+  else if (anchor->AnchorFormat == 2)
     {
-      READ_INT16 (stream, caret->f.f3.Coordinate);
-      if (read_device_table (otf, stream, offset + caret->offset,
-                            &caret->f.f3.DeviceTable) < 0)
-       return -1;
+      READ_UINT16 (stream, anchor->f.f1.AnchorPoint);
+    }
+  else if (anchor->AnchorFormat == 3)
+    {
+      READ_OFFSET (stream, anchor->f.f2.XDeviceTable.offset);
+      READ_OFFSET (stream, anchor->f.f2.YDeviceTable.offset);
+      if (anchor->f.f2.XDeviceTable.offset)
+       {
+         if (read_device_table (otf, stream, offset + anchor->offset,
+                                &anchor->f.f2.XDeviceTable) < 0)
+           return -1;
+       }
+      if (anchor->f.f2.YDeviceTable.offset)
+       {
+         if (read_device_table (otf, stream, offset + anchor->offset,
+                                &anchor->f.f2.YDeviceTable) < 0)
+           return -1;
+       }
     }
   else
-    OTF_ERROR (OTF_ERROR_TABLE, " (Invalid format)");
+    OTF_ERROR (OTF_ERROR_TABLE, " (invalid format)");
+
   return 0;
 }
 
 static int
-read_lig_caret_list (OTF *otf, OTF_Stream *stream, long offset,
-                    OTF_LigCaretList *list)
+read_mark_array (OTF *otf, OTF_Stream *stream, long offset,
+                OTF_MarkArray *array)
 {
-  char *errfmt = "LigCaretList%s";
+  char *errfmt = "MarkArray%s";
   int errret = -1;
-  int i, j;
-
-  if (read_coverage (otf, stream, offset, &list->Coverage) < 0)
-    return -1;
-  READ_UINT16 (stream, list->LigGlyphCount);
-  OTF_MALLOC (list->LigGlyph, list->LigGlyphCount, "");
-  for (i = 0; i < list->LigGlyphCount; i++)
-    READ_OFFSET (stream, list->LigGlyph[i].offset);
-  for (i = 0; i < list->LigGlyphCount; i++)
+  OTF_StreamState state;
+  int i;
+  
+  READ_OFFSET (stream, array->offset);
+  SAVE_STREAM (stream, state);
+  SEEK_STREAM (stream, offset + array->offset);
+  READ_UINT16 (stream, array->MarkCount);
+  OTF_MALLOC (array->MarkRecord, array->MarkCount, "");
+  for (i = 0; i < array->MarkCount; i++)
     {
-      int count;
-
-      SEEK_STREAM (stream, offset + list->LigGlyph[i].offset);
-      READ_UINT16 (stream, count);
-      list->LigGlyph[i].CaretCount = count;
-      OTF_MALLOC (list->LigGlyph[i].CaretValue, count, " (CaretValue)");
-      for (j = 0; j < count; j++)
-       READ_OFFSET (stream, list->LigGlyph[i].CaretValue[j].offset);
-      for (j = 0; j < count; j++)
-       if (read_caret_value (otf, stream, offset + list->LigGlyph[i].offset,
-                             &list->LigGlyph[i].CaretValue[j]) < 0)
-         return -1;
+      READ_UINT16 (stream, array->MarkRecord[i].Class);
+      READ_OFFSET (stream, array->MarkRecord[i].MarkAnchor.offset);
     }
+  for (i = 0; i < array->MarkCount; i++)
+    if (read_anchor (otf, stream, offset + array->offset,
+                    &array->MarkRecord[i].MarkAnchor) < 0)
+      return -1;;
+  RESTORE_STREAM (stream, state);
   return 0;
 }
 
 static int
-read_gdef_header (OTF_Stream *stream, OTF_GDEFHeader *header)
+read_anchor_array (OTF *otf, OTF_Stream *stream, long offset,
+                  unsigned ClassCount, OTF_AnchorArray *array)
 {
+  char *errfmt = "AnchorArray%s";
   int errret = -1;
-
-  READ_FIXED (stream, header->Version);
-  READ_OFFSET (stream, header->GlyphClassDef);
-  READ_OFFSET (stream, header->AttachList);
-  READ_OFFSET (stream, header->LigCaretList);
-  READ_OFFSET (stream, header->MarkAttachClassDef);
+  OTF_StreamState state;
+  int i, j;
+  
+  READ_OFFSET (stream, array->offset);
+  SAVE_STREAM (stream, state);
+  SEEK_STREAM (stream, offset + array->offset);
+  READ_UINT16 (stream, array->Count);
+  OTF_MALLOC (array->AnchorRecord, array->Count, "");
+  for (i = 0; i < array->Count; i++)
+    {
+      OTF_MALLOC (array->AnchorRecord[i].Anchor, ClassCount,
+                 " (AnchorRecord)");
+      for (j = 0; j < ClassCount; j++)
+       READ_OFFSET (stream, array->AnchorRecord[i].Anchor[j].offset);
+    }
+  for (i = 0; i < array->Count; i++)
+    for (j = 0; j < ClassCount; j++)
+      if (read_anchor (otf, stream, offset + array->offset,
+                      &array->AnchorRecord[i].Anchor[j]) < 0)
+       return -1;
+  RESTORE_STREAM (stream, state);
   return 0;
 }
 
-static void *
-read_gdef_table (OTF *otf, OTF_Stream *stream)
+
+static OTF_Class1Record *
+read_class1_record_list (OTF *otf, OTF_Stream *stream, long offset,
+                        unsigned num1, enum OTF_ValueFormat bit1,
+                        unsigned num2, enum OTF_ValueFormat bit2)
 {
-  char *errfmt = "GDEF%s";
+  char *errfmt = "Class1Record%s";
   void *errret = NULL;
-  OTF_GDEF *gdef;
+  OTF_Class1Record *rec;
+  int i, j;
 
-  OTF_CALLOC (gdef, 1, "");
-  read_gdef_header (stream, (OTF_GDEFHeader *) &gdef->header);
-  if (gdef->header.GlyphClassDef)
-    {
-      gdef->glyph_class_def.offset = gdef->header.GlyphClassDef;
-      read_class_def_without_offset (otf, stream, &gdef->glyph_class_def);
-    }
-  if (gdef->header.AttachList)
-    read_attach_list (otf, stream, gdef->header.AttachList,
-                     &gdef->attach_list);
-  if (gdef->header.LigCaretList)
-    read_lig_caret_list (otf, stream, gdef->header.LigCaretList,
-                        &gdef->lig_caret_list);
-  if (gdef->header.MarkAttachClassDef)
+  OTF_MALLOC (rec, num1, "");
+  for (i = 0; i < num1; i++)
     {
-      gdef->mark_attach_class_def.offset = gdef->header.MarkAttachClassDef;
-      read_class_def_without_offset (otf, stream, &gdef->mark_attach_class_def);
+      OTF_CALLOC (rec[i].Class2Record, num2, " (Class2Record)");
+      for (j = 0; j < num2; j++)
+       {
+         if (read_value_record (otf, stream, offset,
+                                bit1, &rec[i].Class2Record[j].Value1) < 0
+             || read_value_record (otf, stream, offset,
+                                   bit2, &rec[i].Class2Record[j].Value2) < 0)
+           return NULL;
+       }
     }
-
-  return gdef;
+  return rec;
 }
 
-\f
-
-/* cmap */
-
-static void *
-read_cmap_table (OTF *otf, OTF_Stream *stream)
+static int 
+read_lookup_subtable_gpos (OTF *otf, OTF_Stream *stream,
+                          long offset, unsigned type,
+                          OTF_LookupSubTableGPOS *subtable)
 {
-  char *errfmt = "cmap%s";
-  void *errret = NULL;
-  OTF_cmap *cmap;
-  int i;
+  char errfmt[256];
+  int errret = -1;
 
-  OTF_CALLOC (cmap, 1, "");
-  READ_USHORT (stream, cmap->version);
-  READ_USHORT (stream, cmap->numTables);
-  OTF_MALLOC (cmap->EncodingRecord, cmap->numTables, "");
-  for (i = 0; i < cmap->numTables; i++)
-    {
-      READ_USHORT (stream, cmap->EncodingRecord[i].platformID);
-      READ_USHORT (stream, cmap->EncodingRecord[i].encodingID);
-      READ_ULONG (stream, cmap->EncodingRecord[i].offset);
-      if (cmap->EncodingRecord[i].platformID == 3
-         && cmap->EncodingRecord[i].encodingID == 1)
-       cmap->Unicode = cmap->EncodingRecord + i;
-    }
-  for (i = 0; i < cmap->numTables; i++)
+  SEEK_STREAM (stream, offset);
+  READ_UINT16 (stream, subtable->Format);
+  sprintf (errfmt, "GPOS Lookup %d-%d%%s", type, subtable->Format);
+  switch (type)
     {
-      unsigned format;
-
-      SEEK_STREAM (stream, cmap->EncodingRecord[i].offset);
-      READ_USHORT (stream, format);
-      cmap->EncodingRecord[i].subtable.format = format;
-      READ_USHORT (stream, cmap->EncodingRecord[i].subtable.length);
-      if (format == 8 || format == 10 || format == 12)
+    case 1:
+      if (subtable->Format == 1)
        {
-         READ_ULONG (stream, cmap->EncodingRecord[i].subtable.length);
-         READ_ULONG (stream, cmap->EncodingRecord[i].subtable.language);
+         READ_UINT16 (stream, subtable->u.single1.ValueFormat);
+         read_value_record (otf, stream, offset,
+                            subtable->u.single1.ValueFormat,
+                            &subtable->u.single1.Value);
+       }
+      else if (subtable->Format == 2)
+       {
+         OTF_GPOS_Single2 *single2 = &subtable->u.single2;
+         int i;
+
+         READ_UINT16 (stream, single2->ValueFormat);
+         READ_UINT16 (stream, single2->ValueCount);
+         OTF_CALLOC (single2->Value, single2->ValueCount," (ValueRecord)");
+         for (i = 0; i < single2->ValueCount; i++)
+           read_value_record (otf, stream, offset, single2->ValueFormat,
+                              single2->Value + i);
        }
       else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
+
+    case 2:
+      if (subtable->Format == 1)
        {
-         READ_USHORT (stream, cmap->EncodingRecord[i].subtable.language);
+         OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
        }
-      switch (format)
+      else if (subtable->Format == 2)
        {
-       case 0:
-         {
-           OTF_MALLOC (cmap->EncodingRecord[i].subtable.f.f0, 1,
-                       " (EncodingRecord)");
-           READ_BYTES (stream,
-                       cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray,
-                       256);
-         }
-         break;
-
-       case 2:
-         break;
-
-       case 4:
-         {
-           OTF_EncodingSubtable4 *sub4;
-           int segCount;
-           int j;
-           unsigned dummy;
-
-           OTF_MALLOC (sub4, 1, " (EncodingSubtable4)");
-           cmap->EncodingRecord[i].subtable.f.f4 = sub4;
-           READ_USHORT (stream, sub4->segCountX2);
-           segCount = sub4->segCountX2 / 2;
-           READ_USHORT (stream, sub4->searchRange);
-           READ_USHORT (stream, sub4->entrySelector);
-           READ_USHORT (stream, sub4->rangeShift);
-           OTF_MALLOC (sub4->segments, segCount, " (segCount)");
-           for (j = 0; j < segCount; j++)
-             READ_USHORT (stream, sub4->segments[j].endCount);
-           READ_USHORT (stream, dummy);
-           for (j = 0; j < segCount; j++)
-             READ_USHORT (stream, sub4->segments[j].startCount);
-           for (j = 0; j < segCount; j++)
-             READ_SHORT (stream, sub4->segments[j].idDelta);
-           for (j = 0; j < segCount; j++)
-             {
-               unsigned off;
-               unsigned rest = 2 * (segCount - j);
-               
-               READ_USHORT (stream, off);
-               if (off == 0)
-                 sub4->segments[j].idRangeOffset = 0xFFFF;
-               else
-                 sub4->segments[j].idRangeOffset = (off - rest) / 2;
-             }
-           j = (cmap->EncodingRecord[i].subtable.length
-                - (14 + 2 * (segCount * 4 + 1)));
-           sub4->GlyphCount = j / 2;
-           OTF_MALLOC (sub4->glyphIdArray, sub4->GlyphCount, " (GlyphCount)");
-           for (j = 0; j < sub4->GlyphCount; j++)
-             READ_USHORT (stream, sub4->glyphIdArray[j]);
-         }
+         SEEK_STREAM (stream, offset + 2);
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         READ_UINT16 (stream, subtable->u.pair2.ValueFormat1);
+         READ_UINT16 (stream, subtable->u.pair2.ValueFormat2);
+         read_class_def (otf, stream, offset,
+                         &subtable->u.pair2.ClassDef1);
+         read_class_def (otf, stream, offset,
+                         &subtable->u.pair2.ClassDef2);
+         READ_UINT16 (stream, subtable->u.pair2.Class1Count);
+         READ_UINT16 (stream, subtable->u.pair2.Class2Count);
+         subtable->u.pair2.Class1Record
+           = read_class1_record_list (otf, stream, offset,
+                                      subtable->u.pair2.Class1Count,
+                                      subtable->u.pair2.ValueFormat1,
+                                      subtable->u.pair2.Class2Count,
+                                      subtable->u.pair2.ValueFormat2);
        }
-    }
-  return cmap;
-}
-
-\f
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
+      
+    case 3:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+      break;
 
-/* TABLE: name */
+    case 4:
+      if (subtable->Format == 1)
+       {
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         read_coverage (otf, stream, offset,
+                        &subtable->u.mark_base1.BaseCoverage);
+         READ_UINT16 (stream, subtable->u.mark_base1.ClassCount);
+         read_mark_array (otf, stream, offset,
+                          &subtable->u.mark_base1.MarkArray);
+         read_anchor_array (otf, stream, offset,
+                            subtable->u.mark_base1.ClassCount,
+                            &subtable->u.mark_base1.BaseArray);
+       }
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
 
-static char *
-read_name (OTF *otf, OTF_Stream *stream, OTF_NameRecord *rec, int bytes)
-{
-  char *errfmt = "nameID (%d)";
-  void *errret = NULL;
-  OTF_StreamState state;
-  char *str;
-  int i;
-  int c;
+    case 5:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+      break;
 
-  SAVE_STREAM (stream, state);
-  SEEK_STREAM (stream, stream->pos + rec->offset);
+    case 6:
+      if (subtable->Format == 1)
+       {
+         read_coverage (otf, stream, offset, &subtable->Coverage);
+         read_coverage (otf, stream, offset,
+                        &subtable->u.mark_mark1.Mark2Coverage);
+         READ_UINT16 (stream, subtable->u.mark_base1.ClassCount);
+         read_mark_array (otf, stream, offset,
+                          &subtable->u.mark_mark1.Mark1Array);
+         read_anchor_array (otf, stream, offset,
+                            subtable->u.mark_mark1.ClassCount,
+                            &subtable->u.mark_mark1.Mark2Array);
+       }
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
 
-  if (bytes == 1)
-    {
-      OTF_MALLOC (str, rec->length + 1, (void *) rec->nameID);
-      READ_BYTES (stream, str, rec->length);
-      for (i = 0; i < rec->length; i++)
-       if (str[i] < 0)
-         str[i] = '?';
-    }
-  else if (bytes == 2)
-    {
-      OTF_MALLOC (str, rec->length / 2 + 1, (void *) rec->nameID);
-      for (i = 0; i < rec->length / 2; i++)
+    case 7:
+      if (subtable->Format == 1)
+       {
+         if (read_context1 (otf, stream, offset, &subtable->Coverage,
+                            &subtable->u.context1) < 0)
+           return errret;
+       }
+      else if (subtable->Format == 2)
        {
-         READ_USHORT (stream, c);
-         if (c >= 128)
-           c = '?';
-         str[i] = c;
+         if (read_context2 (otf, stream, offset, &subtable->Coverage,
+                            &subtable->u.context2) < 0)
+           return errret;
        }
-    }
-  else if (bytes == 4)
-    {
-      OTF_MALLOC (str, rec->length / 4 + 1, (void *) rec->nameID);
-      for (i = 0; i < rec->length / 4; i++)
+      else if (subtable->Format == 3)
        {
-         READ_ULONG (stream, c);
-         if (c >= 128)
-           c = '?';
-         str[i] = c;
+         if (read_context3 (otf, stream, offset, &subtable->Coverage,
+                            &subtable->u.context3) < 0)
+           return errret;
+       }
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
+
+    case 8:
+      if (subtable->Format == 1)
+       {
+         if (read_chain_context1 (otf, stream, offset, &subtable->Coverage,
+                                  &subtable->u.chain_context1) < 0)
+           return errret;
+       }
+      else if (subtable->Format == 2)
+       {
+         if (read_chain_context2 (otf, stream, offset, &subtable->Coverage,
+                                  &subtable->u.chain_context2) < 0)
+           return errret;
+       }
+      else if (subtable->Format == 3)
+       {
+         if (read_chain_context3 (otf, stream, offset, &subtable->Coverage,
+                                  &subtable->u.chain_context3) < 0)
+           return errret;
        }
+      else
+       OTF_ERROR (OTF_ERROR_TABLE, " (Invalid SubFormat)");
+      break;
+
+    case 9:
+      OTF_ERROR (OTF_ERROR_TABLE, " (not yet supported)");
+      break;
+
+    default:
+      OTF_ERROR (OTF_ERROR_TABLE, " (Invalid LookupType)");
     }
-  str[i] = '\0';
-  RESTORE_STREAM (stream, state);
-  return str;
+  return 0;
 }
 
 static void *
-read_name_table (OTF *otf, OTF_Stream *stream)
+read_gpos_table (OTF *otf, OTF_Stream *stream)
 {
-  char *errfmt = "name%s";
-  void *errret = NULL;
-  OTF_name *name;
-  int i;
+  return read_gsub_gpos_table (otf, stream, 0);
+}
 
-  OTF_CALLOC (name, 1, "");
-  READ_USHORT (stream, name->format);
-  READ_USHORT (stream, name->count);
-  READ_USHORT (stream, name->stringOffset);
-  OTF_MALLOC (name->nameRecord, name->count, "");
-  for (i = 0; i < name->count; i++)
-    {
-      OTF_NameRecord *rec = name->nameRecord + i;
+\f
+#if 0
+/* BASE */
 
-      READ_USHORT (stream, rec->platformID);
-      READ_USHORT (stream, rec->encodingID);
-      READ_USHORT (stream, rec->languageID);
-      READ_USHORT (stream, rec->nameID);
-      READ_USHORT (stream, rec->length);
-      READ_USHORT (stream, rec->offset);
-    }
-  for (i = 0; i < name->count; i++)
-    {
-      OTF_NameRecord *rec = name->nameRecord + i;
-      int nameID = rec->nameID;
+static OTF_BASE *
+read_base_table (OTF_Stream *stream, long offset)
+{
+  OTF_BASE *base;
 
-      if (nameID <= OTF_max_nameID
-         && ! name->name[nameID])
-       {
-         if (rec->platformID == 0)
-           name->name[nameID] = read_name (otf, stream, rec,
-                                           rec->encodingID <= 3 ? 2 : 4);
-         else if (rec->platformID == 1
-                  && rec->encodingID == 0)
-           name->name[nameID] = read_name (otf, stream, rec, 1);
-         else if (rec->platformID == 3
-                  && (rec->encodingID == 1 || rec->encodingID == 10))
-           name->name[nameID] = read_name (otf, stream,
-                                           rec, rec->encodingID == 1 ? 2 : 4);
-       }
-    }
+  OTF_MALLOC (base, 1);
 
-  return name;
+  return base;
 }
 
 \f
+/* JSTF */
 
-/* APIs */
+static OTF_JSTF *
+read_jstf_table (OTF_Stream *stream, long offset)
+{
+  OTF_JSTF *jstf;
 
-OTF_Tag
-OTF_tag (char *name)
+  OTF_MALLOC (jstf, 1);
+
+  return jstf;
+}
+#endif /* 0 */
+\f
+/*** (1-11) Structure for OTF */
+
+int
+read_offset_table (OTF *otf, OTF_Stream *stream, OTF_OffsetTable *table)
+{  
+  int errret = -1;
+
+  READ_FIXED (stream, table->sfnt_version);
+  READ_USHORT (stream, table->numTables);
+  READ_USHORT (stream, table->searchRange);
+  READ_USHORT (stream, table->enterSelector);
+  READ_USHORT (stream, table->rangeShift);
+  return 0;
+}
+
+static OTF_Tag
+read_table_directory (OTF_Stream *stream, OTF_TableDirectory *table)
 {
-  unsigned char *p = (unsigned char *) name;
+  int errret = 0;
+  OTF_Tag tag;
 
-  if (! name)
-    return (OTF_Tag) 0;
-  return (OTF_Tag) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+  READ_TAG (stream, tag);
+  table->tag = tag;
+  table->name[0] = tag >> 24;
+  table->name[1] = (tag >> 16) & 0xFF;
+  table->name[0] = (tag >> 8) & 0xFF;
+  table->name[0] = tag >> 8;
+  table->name[0] = '\0';
+  READ_ULONG (stream, table->checkSum);
+  READ_ULONG (stream, table->offset);
+  READ_ULONG (stream, table->length);
+  return tag;
 }
 
-void
-OTF_tag_name (OTF_Tag tag, char *name)
+static int
+read_header_part (OTF *otf, FILE *fp)
 {
-  name[0] = (char) (tag >> 24);
-  name[1] = (char) ((tag >> 16) & 0xFF);
-  name[2] = (char) ((tag >> 8) & 0xFF);
-  name[3] = (char) (tag & 0xFF);
-  name[4] = '\0';
+  char *errfmt = "otf header%s";
+  int errret = -1;
+  OTF_Tag head_tag, name_tag, cmap_tag, gdef_tag, gsub_tag, gpos_tag;
+  OTF_Stream *stream;
+  int i;
+  OTF_InternalData *internal_data = (OTF_InternalData *) otf->internal_data;
+
+  internal_data->table_info[OTF_TABLE_TYPE_HEAD].address = (void *) &otf->head;
+  internal_data->table_info[OTF_TABLE_TYPE_HEAD].reader = read_head_table;
+  internal_data->table_info[OTF_TABLE_TYPE_NAME].address = (void *) &otf->name;
+  internal_data->table_info[OTF_TABLE_TYPE_NAME].reader = read_name_table;
+  internal_data->table_info[OTF_TABLE_TYPE_CMAP].address = (void *) &otf->cmap;
+  internal_data->table_info[OTF_TABLE_TYPE_CMAP].reader = read_cmap_table;
+  internal_data->table_info[OTF_TABLE_TYPE_GDEF].address = (void *) &otf->gdef;
+  internal_data->table_info[OTF_TABLE_TYPE_GDEF].reader = read_gdef_table;
+  internal_data->table_info[OTF_TABLE_TYPE_GSUB].address = (void *) &otf->gsub;
+  internal_data->table_info[OTF_TABLE_TYPE_GSUB].reader = read_gsub_table;
+  internal_data->table_info[OTF_TABLE_TYPE_GPOS].address = (void *) &otf->gpos;
+  internal_data->table_info[OTF_TABLE_TYPE_GPOS].reader = read_gpos_table;
+
+  head_tag = OTF_tag ("head");
+  name_tag = OTF_tag ("name");
+  cmap_tag = OTF_tag ("cmap");
+  gdef_tag = OTF_tag ("GDEF");
+  gsub_tag = OTF_tag ("GSUB");
+  gpos_tag = OTF_tag ("GPOS");
+
+  stream = make_stream ();
+  if (! stream)
+    return -1;
+
+  internal_data->header_stream = stream;
+  
+  /* Size of Offset Table is 12 bytes.  */
+  if (setup_stream (stream, fp, 0, 12, "Offset Table") < 0)
+    return -1;
+  if (read_offset_table (otf, stream, &otf->offset_table) < 0)
+    return -1;
+
+  /* Size of each Table Directory is 16 bytes.  */
+  if (setup_stream (stream, fp, 12, 16 * otf->offset_table.numTables,
+                   "Table Directory") < 0)
+    return -1;
+
+  OTF_CALLOC (otf->table_dirs, otf->offset_table.numTables, " (OffsetTable)");
+  for (i = 0; i < otf->offset_table.numTables; i++)
+    {
+      OTF_Tag tag = read_table_directory (stream, otf->table_dirs + i);
+      OTF_TableInfo *table_info = NULL;
+
+      if (! tag)
+       return -1;
+      if (tag == head_tag)
+       table_info = internal_data->table_info + OTF_TABLE_TYPE_HEAD;
+      else if (tag == name_tag)
+       table_info = internal_data->table_info + OTF_TABLE_TYPE_NAME;
+      else if (tag == cmap_tag)
+       table_info = internal_data->table_info + OTF_TABLE_TYPE_CMAP;
+      else if (tag == gdef_tag)
+       table_info = internal_data->table_info + OTF_TABLE_TYPE_GDEF;
+      else if (tag == gsub_tag)
+       table_info = internal_data->table_info + OTF_TABLE_TYPE_GSUB;
+      else if (tag == gpos_tag)
+       table_info = internal_data->table_info + OTF_TABLE_TYPE_GPOS;
+
+      if (table_info)
+       {
+         table_info->stream = make_stream ();
+         if (setup_stream (table_info->stream, fp,
+                           otf->table_dirs[i].offset,
+                           otf->table_dirs[i].length,
+                           otf->table_dirs[i].name) < 0)
+           return -1;
+       }
+    }
+
+  internal_data->header_stream = NULL;
+  free_stream (stream);
+  return 0;
 }
 
+\f
+/*** (2) APIs for reading OTF */
+
+/*** (2-1) OTF_open() */
 
-/* We can't use memory allocation macros in the following functions
-   because those macros returns from the functions before freeing
-   memory previously allocated.  */
+/* Note: We can't use memory allocation macros in the following
+   functions because those macros return from the functions before
+   freeing memory previously allocated.  */
 
 OTF *
 OTF_open (char *otf_name)
@@ -2251,6 +2291,7 @@ OTF_open (char *otf_name)
   return otf;
 }
 
+/*** (2-2) OTF_close() */
 
 void
 OTF_close (OTF *otf)
@@ -2283,6 +2324,7 @@ OTF_close (OTF *otf)
   free (otf);
 }
 
+/*** (2-3) OTF_get_table() */
 
 int
 OTF_get_table (OTF *otf, char *name)
@@ -2330,3 +2372,26 @@ OTF_get_table (OTF *otf, char *name)
 
   return 0;
 }
+
+\f
+/*** (5) APIs miscellaneous ***/
+
+OTF_Tag
+OTF_tag (char *name)
+{
+  unsigned char *p = (unsigned char *) name;
+
+  if (! name)
+    return (OTF_Tag) 0;
+  return (OTF_Tag) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
+}
+
+void
+OTF_tag_name (OTF_Tag tag, char *name)
+{
+  name[0] = (char) (tag >> 24);
+  name[1] = (char) ((tag >> 16) & 0xFF);
+  name[2] = (char) ((tag >> 8) & 0xFF);
+  name[3] = (char) (tag & 0xFF);
+  name[4] = '\0';
+}