/* otfdump.c -- Dump OpenType Layout Tables. Copyright (C) 2003, 2004, 2008, 2009, 2010 National Institute of Advanced Industrial Science and Technology (AIST) Registration Number H15PRO167 This file is part of libotf. Libotf is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Libotf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library, in a file named COPYING; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include /* Indented print. */ #define IPRINT printf("\n%*s", indent * 2, ""), printf static void dump_tag (OTF_Tag tag) { printf ("(tag \""); putchar (tag >> 24); putchar ((tag >> 16) & 0xFF); putchar ((tag >> 8) & 0xFF); putchar (tag & 0xFF); printf ("\" #x%04X)", tag); } /* HEAD */ static void dump_offset_table (int indent, OTF_OffsetTable *table) { IPRINT ("(OffsetTable"); indent++; IPRINT ("(sfnt-version %d.%d)", table->sfnt_version.high, table->sfnt_version.low); IPRINT ("(numTables %d)", table->numTables); IPRINT ("(searchRange %d)", table->searchRange); IPRINT ("(enterSelector %d)", table->enterSelector); IPRINT ("(rangeShift %d))", table->rangeShift); } static void dump_table_directory (int indent, OTF_TableDirectory *table, int idx) { IPRINT ("(Table %d ", idx); dump_tag (table->tag); indent++; IPRINT ("(checkSum %08X) (offset #x%08X) (length: #x%08X))", table->checkSum, table->offset, table->length); } /* head */ static void dump_head_table (int indent, OTF_head *head) { IPRINT ("(head"); indent++; IPRINT ("(TableVersionNumber %d.%d)", head->TableVersionNumber.high, head->TableVersionNumber.low); IPRINT ("(fontRevision %d.%d)", head->fontRevision.high, head->fontRevision.low); IPRINT ("(checkSumAdjustment #x%04X)", head->checkSumAdjustment); IPRINT ("(magicNumber #x%04X)", head->magicNumber); IPRINT ("(flags #x%04X)", head->flags); IPRINT ("(unitsPerEm %d)", head->unitsPerEm); printf (")"); } /* COMMON */ static void dump_glyph_ids (int indent, char *title, OTF_GlyphID *ids, unsigned count) { IPRINT ("(%s (count %d)", title, count); while (count-- > 0) { printf (" #x%04X", *ids); ids++; } printf (")"); } static int * dump_coverage (int indent, char *title, OTF_Coverage *coverage) { int i; int *char_list; IPRINT ("(%sCoverage (CoverageFormat %d)", (title ? title : ""), coverage->CoverageFormat); indent++; if (coverage->CoverageFormat == 1) { dump_glyph_ids (indent, "GlyphArray", coverage->table.GlyphArray, coverage->Count); char_list = malloc (sizeof (int) * (coverage->Count + 1)); for (i = 0; i < coverage->Count; i++) char_list[i] = coverage->table.GlyphArray[i]; char_list[i] = -1; } else { int n, c; IPRINT ("(RangeCount %d)", coverage->Count); indent++; for (i = n = 0; i < coverage->Count; i++) { IPRINT ("(Range (%d) (Start #x%04X) (End #x%04X)", i, coverage->table.RangeRecord[i].Start, coverage->table.RangeRecord[i].End); indent++; IPRINT ("(StartCoverageIndex %d))", coverage->table.RangeRecord[i].StartCoverageIndex); indent--; n += (coverage->table.RangeRecord[i].End - coverage->table.RangeRecord[i].Start + 1); } char_list = malloc (sizeof (int) * (n + 1)); for (i = n = 0; i < coverage->Count; i++) for (c = coverage->table.RangeRecord[i].Start; c <= coverage->table.RangeRecord[i].End; c++) char_list[n++] = c; char_list[n] = -1; } printf (")"); return char_list; } static void dump_coverage_list (int indent, char *title, OTF_Coverage *coverage, unsigned num) { int i; IPRINT ("(%s %d)", title, num); for (i = 0; i < num; i++) free (dump_coverage (indent, NULL, coverage + i)); } static void dump_language_system (int indent, int index, OTF_Tag tag, OTF_Offset offset, OTF_LangSys *langsys) { int i; IPRINT ("(LangSys "); if (index >= 0) printf ("(%d) ", index); if (tag) dump_tag (tag); else printf ("DefaultLangSys"); printf (" (Offset #x%04X)", offset); indent++; IPRINT ("(LookupOrder #x%04X)", langsys->LookupOrder); IPRINT ("(ReqFeatureIndex %d)", langsys->ReqFeatureIndex); IPRINT ("(FeatureCount %d)", langsys->FeatureCount); if (langsys->FeatureCount) { IPRINT ("(FeatureIndex"); for (i = 0; i < langsys->FeatureCount; i++) printf (" %d", langsys->FeatureIndex[i]); printf (")"); } printf (")"); } static void dump_script_list (int indent, OTF_ScriptList *list) { int i, j; IPRINT ("(ScriptList (count %d)", list->ScriptCount); indent++; for (i = 0; i < list->ScriptCount; i++) { OTF_Script *script = list->Script + i; IPRINT ("(Script (%d) ", i); dump_tag (list->Script[i].ScriptTag); printf (" (Offset #x%04X)", list->Script[i].offset); indent++; IPRINT ("(DefaultLangSysOffset #x%04X)", script->DefaultLangSysOffset); if (script->DefaultLangSysOffset) dump_language_system (indent, -1, 0, script->DefaultLangSysOffset, &script->DefaultLangSys); IPRINT ("(LangSysCount %d)", script->LangSysCount); for (j = 0; j < script->LangSysCount; j++) dump_language_system (indent, j, script->LangSysRecord[j].LangSysTag, script->LangSysRecord[j].LangSys, script->LangSys + j); printf (")"); indent--; } printf (")"); } static void dump_feature_list (int indent, OTF_FeatureList *list) { int i, j; IPRINT ("(FeatureList (count %d)", list->FeatureCount); indent++; for (i = 0; i < list->FeatureCount; i++) { OTF_Feature *feature = list->Feature + i; IPRINT ("(Feature (%d) ", i); dump_tag (list->Feature[i].FeatureTag); printf (" (Offset #x%04X)", list->Feature[i].offset); printf (" (LookupCount %d)", feature->LookupCount); if (feature->LookupCount) { indent++; IPRINT ("(LookupListIndex"); for (j = 0; j < feature->LookupCount; j++) printf (" %d", feature->LookupListIndex[j]); printf (")"); indent--; } printf (")"); } printf (")"); } static void dump_class_def (int indent, char *title, OTF_ClassDef *class) { IPRINT ("(%s (offset #x%04X) (ClassFormat %d)", (title ? title : "ClassDef"), class->offset, class->ClassFormat); if (class->offset) { indent++; if (class->ClassFormat == 1) { IPRINT ("(StartGlyph #x%04X)", class->f.f1.StartGlyph); dump_glyph_ids (indent, "ClassValueArray", (OTF_GlyphID *) class->f.f1.ClassValueArray, class->f.f1.GlyphCount); } else if (class->ClassFormat == 2) { int i; IPRINT ("(ClassRangeCount %d)", class->f.f2.ClassRangeCount); IPRINT ("(ClassRangeRecord"); indent++; for (i = 0; i < class->f.f2.ClassRangeCount; i++) IPRINT ("((Start #x%04X) (End #x%04X) (class %d))", class->f.f2.ClassRangeRecord[i].Start, class->f.f2.ClassRangeRecord[i].End, class->f.f2.ClassRangeRecord[i].Class); printf (")"); } else printf (" UnknownClassFormat"); } printf (")"); } static void dump_device_table (int indent, char *title, OTF_DeviceTable *table) { int i; if (! table->offset) return; IPRINT ("(%s (offset #x%04X)", title, table->offset); indent++; IPRINT ("(StartSize %d) (EndSize %d) (DeltaFormat %d)", table->StartSize, table->EndSize, table->DeltaFormat); if (table->DeltaValue) { IPRINT ("(DeltaValue"); for (i = 0; i < table->EndSize - table->StartSize + 1; i++) printf (" %d", table->DeltaValue[i]); printf (")"); } printf (")"); } static void dump_value_record (int indent, char *title, OTF_ValueRecord *rec) { IPRINT ("(%s %d %d %d %d", title, rec->XPlacement, rec->YPlacement, rec->XAdvance, rec->YAdvance); indent++; if (rec->XPlaDevice.offset) dump_device_table (indent, "XPlaDevice", &rec->XPlaDevice); if (rec->YPlaDevice.offset) dump_device_table (indent, "YPlaDevice", &rec->YPlaDevice); if (rec->XAdvDevice.offset) dump_device_table (indent, "XAdvDevice", &rec->XAdvDevice); if (rec->YAdvDevice.offset) dump_device_table (indent, "YAdvDevice", &rec->YAdvDevice); printf (")"); } static void dump_sequence_list (int indent, OTF_Sequence *sequence, unsigned num) { int i; IPRINT ("(SequenceCount %d)", num); for (i = 0; i < num; i++) { IPRINT ("(Sequence (%d) (offset #x%04X)", i, sequence[i].offset); dump_glyph_ids (indent + 1, "Substitute", sequence[i].Substitute, sequence[i].GlyphCount); printf (")"); } } static void dump_alternate_set_list (int indent, OTF_AlternateSet *altset, unsigned num) { int i; IPRINT ("(AlternateSetCount %d)", num); for (i = 0; i < num; i++) { IPRINT ("(AlternateSet (%d) (offset #x%04X)", i, altset[i].offset); dump_glyph_ids (indent + 1, "Alternate", altset[i].Alternate, altset[i].GlyphCount); printf (")"); } } static void dump_ligature_set_list (int indent, int *char_list, OTF_LigatureSet *ligset, unsigned num) { int i, j, k; IPRINT ("(LigSetCount %d)", num); for (i = 0; i < num; i++) { IPRINT ("(LigatureSet (%d) (offset #x%04X) (count %d)", i, ligset[i].offset, ligset[i].LigatureCount); indent++; for (j = 0; j < ligset[i].LigatureCount; j++) { IPRINT ("(Ligature (%d) (offset #x%04X)", j, ligset[i].Ligature[j].offset); indent++; IPRINT ("(LigGlyph #x%04X)", ligset[i].Ligature[j].LigGlyph); dump_glyph_ids (indent, "Component", ligset[i].Ligature[j].Component, ligset[i].Ligature[j].CompCount - 1); IPRINT ("(i.e. #x%04X", char_list[i]); for (k = 0; k < ligset[i].Ligature[j].CompCount - 1; k++) printf (" #x%04X", ligset[i].Ligature[j].Component[k]); printf (" = #x%04X)", ligset[i].Ligature[j].LigGlyph); printf (")"); indent--; } indent--; printf (")"); } } static void dump_pair_set_list (int indent, unsigned count, OTF_PairSet *set) { int i, j; for (i = 0; i < count; i++) { IPRINT ("(PairSet (%d)", i); indent++; for (j = 0; j < set[i].PairValueCount; j++) { IPRINT ("(PairValueRecord (%d)", j); indent++; IPRINT ("(SecondGlyph #x%04X)", set[i].PairValueRecord[j].SecondGlyph); dump_value_record (indent, "Value1", &set[i].PairValueRecord[j].Value1); dump_value_record (indent, "Value2", &set[i].PairValueRecord[j].Value2); printf (")"); indent--; } printf (")"); indent--; } } static void dump_class1_record_list (int indent, unsigned Class1Count, unsigned Class2Count, OTF_Class1Record *rec) { int i, j; for (i = 0; i < Class1Count; i++) { IPRINT ("(Class1Record (%d)", i); indent++; for (j = 0; j < Class2Count; j++) { IPRINT ("(Class2Record (%d)", j); indent++; dump_value_record (indent, "Value1", &rec[i].Class2Record[j].Value1); dump_value_record (indent, "Value2", &rec[i].Class2Record[j].Value2); printf (")"); indent--; } printf (")"); indent--; } } static void dump_anchor (int indent, OTF_Anchor *anchor) { if (anchor->offset == 0) return; IPRINT ("(Anchor (offset #x%04X) (AnchorFormat %d)", anchor->offset, anchor->AnchorFormat); indent++; IPRINT ("(XCoordinate %d) (YCoordinate %d)", anchor->XCoordinate, anchor->YCoordinate); if (anchor->AnchorFormat == 1) ; else if (anchor->AnchorFormat == 2) IPRINT ("(AnchorPoint %d)", anchor->f.f1.AnchorPoint); else { dump_device_table (indent, "XDeviceTable", &anchor->f.f2.XDeviceTable); dump_device_table (indent, "YDeviceTable", &anchor->f.f2.YDeviceTable); } printf (")"); } static void dump_entry_exit_list (int indent, unsigned count, OTF_EntryExitRecord *rec) { int i; for (i = 0; i < count; i++) { IPRINT ("(EntryExitRecord (%d)", i); indent++; dump_anchor (indent, &rec[i].EntryAnchor); dump_anchor (indent, &rec[i].EntryAnchor); printf (")"); indent--; } } static void dump_mark_array (int indent, OTF_MarkArray *array) { int i; IPRINT ("(MarkArray (MarkCount %d)", array->MarkCount); indent++; for (i = 0; i < array->MarkCount; i++) { IPRINT ("(MarkRecord (%d) (Class %d)", i, array->MarkRecord[i].Class); dump_anchor (indent + 1, &array->MarkRecord[i].MarkAnchor); printf (")"); } printf (")"); } static void dump_anchor_array (int indent, unsigned ClassCount, OTF_AnchorArray *array) { int i, j; IPRINT ("(AnchorArray (Count %d)", array->Count); indent++; for (i = 0; i < array->Count; i++) { IPRINT ("(AnchorRecord (%d) ", i); for (j = 0; j < ClassCount; j++) dump_anchor (indent + 1, array->AnchorRecord[i].Anchor + j); printf (")"); } printf (")"); } static void dump_lookup_record_list (int indent, OTF_LookupRecord *rec, unsigned num) { int i; IPRINT ("(LookupCount %d)", num); for (i = 0; i < num; i++) { IPRINT ("(LookupRecord (%d)", i); indent++; IPRINT ("(SequenceIndex %d)", rec[i].SequenceIndex); IPRINT ("(LookupListIndex %d))", rec[i].LookupListIndex); indent--; } } static void dump_lookup_subtable_gsub (int indent, int index, unsigned type, OTF_LookupSubTableGSUB *subtable); static void dump_lookup_subtable_gpos (int indent, int index, unsigned type, OTF_LookupSubTableGPOS *subtable); static void dump_lookup_list (int indent, OTF_LookupList *list, int gsub) { int i, j; IPRINT ("(LookupList (count %d)", list->LookupCount); indent++; for (i = 0; i < list->LookupCount; i++) { OTF_Lookup *lookup = list->Lookup + i; IPRINT ("(Lookup (%d) (Offset #x%04X)", i, lookup->offset); printf (" (Type %d) (Flag #x%04X) (SubTableCount %d)", lookup->LookupType, lookup->LookupFlag, lookup->SubTableCount); if (gsub) for (j = 0; j < lookup->SubTableCount; j++) dump_lookup_subtable_gsub (indent + 1, j, lookup->LookupType, lookup->SubTable.gsub + j); else for (j = 0; j < lookup->SubTableCount; j++) dump_lookup_subtable_gpos (indent + 1, j, lookup->LookupType, lookup->SubTable.gpos + j); printf (")"); } printf (")"); } static void dump_rule_list (int indent, OTF_Rule *rule, int count) { int i; IPRINT ("(RuleCount %d)", count); for (i = 0; i < count; i++) { IPRINT ("(Rule (%d)", i); indent++; IPRINT ("(GlyphCount %d)", rule[i].GlyphCount); IPRINT ("(LookupCount %d)", rule[i].LookupCount); dump_glyph_ids (indent, "Input", rule[i].Input, rule[i].GlyphCount - 1); dump_lookup_record_list (indent, rule[i].LookupRecord, rule[i].LookupCount); printf (")"); indent--; } } static void dump_rule_set_list (int indent, OTF_RuleSet *set, int count) { int i; IPRINT ("(RuleSetCount %d)", count); for (i = 0; i < count; i++) { IPRINT ("(RuleSet (%d)", i); dump_rule_list (indent + 1, set[i].Rule, set[i].RuleCount); printf (")"); } } static void dump_class_rule_list (int indent, OTF_ClassRule *rule, int count) { int i, j; IPRINT ("(ClassRuleCnt %d)", count); for (i = 0; i < count; i++) { IPRINT ("(ClassRule (%d)", i); indent++; IPRINT ("(GlyphCount %d)", rule[i].GlyphCount); IPRINT ("(LookupCount %d)", rule[i].LookupCount); IPRINT ("(Class"); for (j = 0; j < rule[i].GlyphCount - 1; j++) printf (" %d", rule[i].Class[j]); printf (")"); dump_lookup_record_list (indent, rule[i].LookupRecord, rule[i].LookupCount); printf (")"); indent--; } } static void dump_class_set_list (int indent, OTF_ClassSet *set, int count) { int i; IPRINT ("(ClassSetCount %d)", count); for (i = 0; i < count; i++) if (set[i].offset) { IPRINT ("(ClassSet (%d)", i); dump_class_rule_list (indent + 1, set[i].ClassRule, set[i].ClassRuleCnt); printf (")"); } } static void dump_chain_rule_list (int indent, OTF_ChainRule *rule, int count) { int i; IPRINT ("(ChainRuleCount %d)", count); for (i = 0; i < count; i++) { IPRINT ("(ChainRule (%d)", i); dump_glyph_ids (indent + 1, "Backtrack", rule[i].Backtrack, rule[i].BacktrackGlyphCount); dump_glyph_ids (indent + 1, "Input", rule[i].Input, rule[i].InputGlyphCount - 1); dump_glyph_ids (indent + 1, "LookAhead", rule[i].LookAhead, rule[i].LookaheadGlyphCount); dump_lookup_record_list (indent + 1, rule[i].LookupRecord, rule[i].LookupCount); printf (")"); } } static void dump_chain_rule_set_list (int indent, OTF_ChainRuleSet *set, int count) { int i; IPRINT ("(ChainRuleSetCount %d)", count); for (i = 0; i < count; i++) { IPRINT ("(ChainRuleSet (%d)", i); dump_chain_rule_list (indent + 1, set[i].ChainRule, set[i].ChainRuleCount); printf (")"); } } static void dump_chain_class_rule_list (int indent, OTF_ChainClassRule *rule, int count) { int i; IPRINT ("(ChainClassRuleCount %d)", count); for (i = 0; i < count; i++) { IPRINT ("(ChainClassRule (%d)", i); dump_glyph_ids (indent + 1, "Backtrack", rule[i].Backtrack, rule[i].BacktrackGlyphCount); dump_glyph_ids (indent + 1, "Input", rule[i].Input, rule[i].InputGlyphCount - 1); dump_glyph_ids (indent + 1, "LookAhead", rule[i].LookAhead, rule[i].LookaheadGlyphCount); dump_lookup_record_list (indent + 1, rule[i].LookupRecord, rule[i].LookupCount); printf (")"); } } static void dump_chain_class_set_list (int indent, OTF_ChainClassSet *set, int count) { int i; IPRINT ("(ChainClassSetCount %d)", count); for (i = 0; i < count; i++) if (set[i].offset) { IPRINT ("(ChainClassSet (%d)", i); dump_chain_class_rule_list (indent + 1, set[i].ChainClassRule, set[i].ChainClassRuleCnt); printf (")"); } } /* GSUB */ static void dump_lookup_subtable_gsub (int indent, int index, unsigned type, OTF_LookupSubTableGSUB *subtable) { IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format); indent++; switch (type) { case 1: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(DeltaGlyhpID #x%04X)", subtable->u.single1.DeltaGlyphID); } else if (subtable->Format == 2) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_glyph_ids (indent, "Substitute", subtable->u.single2.Substitute, subtable->u.single2.GlyphCount); } else printf (" invalid"); break; case 2: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_sequence_list (indent, subtable->u.multiple1.Sequence, subtable->u.multiple1.SequenceCount); } else printf (" invalid"); break; case 3: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_alternate_set_list (indent, subtable->u.alternate1.AlternateSet, subtable->u.alternate1.AlternateSetCount); } else printf (" invalid"); break; case 4: if (subtable->Format == 1) { int *char_list = dump_coverage (indent, NULL, &subtable->Coverage); dump_ligature_set_list (indent, char_list, subtable->u.ligature1.LigatureSet, subtable->u.ligature1.LigSetCount); free (char_list); } else printf (" invalid"); break; case 5: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_rule_set_list (indent, subtable->u.context1.RuleSet, subtable->u.context1.RuleSetCount); } else if (subtable->Format == 2) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, NULL, &subtable->u.context2.ClassDef); dump_class_set_list (indent, subtable->u.context2.ClassSet, subtable->u.context2.ClassSetCnt); } else if (subtable->Format == 3) { dump_coverage_list (indent, "Coverage", subtable->u.context3.Coverage, subtable->u.context3.GlyphCount); dump_lookup_record_list (indent, subtable->u.context3.LookupRecord, subtable->u.context3.LookupCount); } else printf (" invalid"); break; case 6: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_chain_rule_set_list (indent, subtable->u.chain_context1.ChainRuleSet, subtable->u.chain_context1.ChainRuleSetCount); } else if (subtable->Format == 2) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, "BacktrackClassDef", &subtable->u.chain_context2.BacktrackClassDef); dump_class_def (indent, "InputClassDef", &subtable->u.chain_context2.InputClassDef); dump_class_def (indent, "LookaheadClassDef", &subtable->u.chain_context2.LookaheadClassDef); dump_chain_class_set_list (indent, subtable->u.chain_context2.ChainClassSet, subtable->u.chain_context2.ChainClassSetCnt); } else if (subtable->Format == 3) { dump_coverage_list (indent, "BackTrackGlyphCount", subtable->u.chain_context3.Backtrack, subtable->u.chain_context3.BacktrackGlyphCount); dump_coverage_list (indent, "InputGlyphCount", subtable->u.chain_context3.Input, subtable->u.chain_context3.InputGlyphCount); dump_coverage_list (indent, "LookaheadGlyphCount", subtable->u.chain_context3.LookAhead, subtable->u.chain_context3.LookaheadGlyphCount); dump_lookup_record_list (indent, subtable->u.chain_context3.LookupRecord, subtable->u.chain_context3.LookupCount); } else printf (" invalid"); break; case 7: IPRINT ("(ExtensionLookupType %d)", subtable->u.extension1.ExtensionLookupType); IPRINT ("(ExtensionOffset %d)", subtable->u.extension1.ExtensionOffset); dump_lookup_subtable_gsub (indent, index, subtable->u.extension1.ExtensionLookupType, subtable->u.extension1.ExtensionSubtable); break; case 8: printf (" not-yet-supported"); break; default: printf (" invalid"); } printf (")"); } static void dump_gsub_table (int indent, OTF_GSUB *gsub) { IPRINT ("(GSUB"); indent++; IPRINT ("(Header"); indent++; IPRINT ("(Version %d.%d)", gsub->Version.high, gsub->Version.low); IPRINT ("(ScriptList #x%04X)", gsub->ScriptList.offset); IPRINT ("(FeatureList #x%04X)", gsub->FeatureList.offset); IPRINT ("(LookupList #x%04X))", gsub->LookupList.offset); indent--; dump_script_list (indent, &gsub->ScriptList); dump_feature_list (indent, &gsub->FeatureList); dump_lookup_list (indent, &gsub->LookupList, 1); printf (")"); } /* GPOS */ static void dump_lookup_subtable_gpos (int indent, int index, unsigned type, OTF_LookupSubTableGPOS *subtable) { IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format); indent++; switch (type) { case 1: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(ValueFormat #x%04X)", subtable->u.single1.ValueFormat); dump_value_record (indent, "Value", &subtable->u.single1.Value); } else if (subtable->Format == 2) { int i; free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(ValueFormat #x%04X)", subtable->u.single2.ValueFormat); IPRINT ("(ValueCount %d)", subtable->u.single2.ValueCount); for (i = 0; i < subtable->u.single2.ValueCount; i++) dump_value_record (indent, "Value", &subtable->u.single2.Value[i]); } else printf (" invalid"); break; case 2: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(ValueFormat1 #x%04X)", subtable->u.pair1.ValueFormat1); IPRINT ("(ValueFormat2 #x%04X)", subtable->u.pair1.ValueFormat2); dump_pair_set_list (indent, subtable->u.pair1.PairSetCount, subtable->u.pair1.PairSet); } else if (subtable->Format == 2) { free (dump_coverage (indent, NULL, &subtable->Coverage)); IPRINT ("(ValueFormat1 #x%04X)", subtable->u.pair2.ValueFormat1); IPRINT ("(ValueFormat2 #x%04X)", subtable->u.pair2.ValueFormat2); dump_class_def (indent, "ClassDef1", &subtable->u.pair2.ClassDef1); dump_class_def (indent, "ClassDef2", &subtable->u.pair2.ClassDef2); IPRINT ("(Class1Count %d)", subtable->u.pair2.Class1Count); IPRINT ("(Class2Count %d)", subtable->u.pair2.Class2Count); dump_class1_record_list (indent, subtable->u.pair2.Class1Count, subtable->u.pair2.Class2Count, subtable->u.pair2.Class1Record); } else printf (" invalid"); break; case 3: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_entry_exit_list (indent, subtable->u.cursive1.EntryExitCount, subtable->u.cursive1.EntryExitRecord); } else printf (" invalid"); break; case 4: if (subtable->Format == 1) { free (dump_coverage (indent, "Mark", &subtable->Coverage)); free (dump_coverage (indent, "Base", &subtable->u.mark_base1.BaseCoverage)); IPRINT ("(ClassCount %d)", subtable->u.mark_base1.ClassCount); dump_mark_array (indent, &subtable->u.mark_base1.MarkArray); dump_anchor_array (indent, subtable->u.mark_base1.ClassCount, &subtable->u.mark_base1.BaseArray); } break; case 5: if (subtable->Format == 1) { OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1; int i, j, k; free (dump_coverage (indent, "Mark", &subtable->Coverage)); free (dump_coverage (indent, "Ligature", &mark_lig1->LigatureCoverage)); IPRINT ("(ClassCount %d)", mark_lig1->ClassCount); dump_mark_array (indent, &mark_lig1->MarkArray); IPRINT ("(LigatureArray (%d)", mark_lig1->LigatureArray.LigatureCount); indent++; for (i = 0; i < mark_lig1->LigatureArray.LigatureCount; i++) { OTF_LigatureAttach *attach = mark_lig1->LigatureArray.LigatureAttach + i; IPRINT ("(LigatureAttach (%d)", attach->ComponentCount); indent++; for (j = 0; j < attach->ComponentCount; j++) { OTF_ComponentRecord *rec = attach->ComponentRecord + j; IPRINT ("(LigatureAnchor (%d)", mark_lig1->ClassCount); for (k = 0; k < mark_lig1->ClassCount; k++) if (rec->LigatureAnchor[k].AnchorFormat) dump_anchor (indent + 1, rec->LigatureAnchor + k); printf (")"); } printf (")"); indent--; } printf (")"); } else printf (" invalid"); break; case 6: if (subtable->Format == 1) { free (dump_coverage (indent, "Mark1", &subtable->Coverage)); free (dump_coverage (indent, "Mark2", &subtable->u.mark_mark1.Mark2Coverage)); IPRINT ("(ClassCount %d)", subtable->u.mark_mark1.ClassCount); dump_mark_array (indent, &subtable->u.mark_mark1.Mark1Array); dump_anchor_array (indent, subtable->u.mark_mark1.ClassCount, &subtable->u.mark_mark1.Mark2Array); } else printf (" invalid"); break; case 7: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_rule_set_list (indent, subtable->u.context1.RuleSet, subtable->u.context1.RuleSetCount); } else if (subtable->Format == 2) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, NULL, &subtable->u.context2.ClassDef); dump_class_set_list (indent, subtable->u.context2.ClassSet, subtable->u.context2.ClassSetCnt); } else if (subtable->Format == 3) { dump_coverage_list (indent, "Coverage", subtable->u.context3.Coverage, subtable->u.context3.GlyphCount); dump_lookup_record_list (indent, subtable->u.context3.LookupRecord, subtable->u.context3.LookupCount); } else printf (" invalid"); break; case 8: if (subtable->Format == 1) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_chain_rule_set_list (indent, subtable->u.chain_context1.ChainRuleSet, subtable->u.chain_context1.ChainRuleSetCount); } else if (subtable->Format == 2) { free (dump_coverage (indent, NULL, &subtable->Coverage)); dump_class_def (indent, "BacktrackClassDef", &subtable->u.chain_context2.BacktrackClassDef); dump_class_def (indent, "InputClassDef", &subtable->u.chain_context2.InputClassDef); dump_class_def (indent, "LookaheadClassDef", &subtable->u.chain_context2.LookaheadClassDef); dump_chain_class_set_list (indent, subtable->u.chain_context2.ChainClassSet, subtable->u.chain_context2.ChainClassSetCnt); } else if (subtable->Format == 3) { dump_coverage_list (indent, "BackTrackGlyphCount", subtable->u.chain_context3.Backtrack, subtable->u.chain_context3.BacktrackGlyphCount); dump_coverage_list (indent, "InputGlyphCount", subtable->u.chain_context3.Input, subtable->u.chain_context3.InputGlyphCount); dump_coverage_list (indent, "LookaheaGlyphCount", subtable->u.chain_context3.LookAhead, subtable->u.chain_context3.LookaheadGlyphCount); dump_lookup_record_list (indent, subtable->u.chain_context3.LookupRecord, subtable->u.chain_context3.LookupCount); } else printf (" invalid"); break; case 9: if (subtable->Format == 1) { IPRINT ("(ExtensionLookupType %d)", subtable->u.extension1.ExtensionLookupType); IPRINT ("(ExtensionOffset %d)", subtable->u.extension1.ExtensionOffset); dump_lookup_subtable_gpos (indent, index, subtable->u.extension1.ExtensionLookupType, subtable->u.extension1.ExtensionSubtable); } else printf (" invalid"); } printf (")"); } static void dump_gpos_table (int indent, OTF_GPOS *gpos) { if (! gpos) return; IPRINT ("(GPOS"); indent++; IPRINT ("(Header"); indent++; IPRINT ("(Version %d.%d)", gpos->Version.high, gpos->Version.low); IPRINT ("(ScriptList #x%04X)", gpos->ScriptList.offset); IPRINT ("(FeatureList #x%04X)", gpos->FeatureList.offset); IPRINT ("(LookupList #x%04X))", gpos->LookupList.offset); indent--; dump_script_list (indent, &gpos->ScriptList); dump_feature_list (indent, &gpos->FeatureList); dump_lookup_list (indent, &gpos->LookupList, 0); printf (")"); } #if 0 static void dump_base_table (OTF_BASE *base) { } static void dump_jstf_table (OTF_JSTF *jstf) { } #endif /* GDEF */ static void dump_gdef_header (int indent, OTF_GDEFHeader *header) { IPRINT ("(Header"); indent++; IPRINT ("(Version %d.%d)", header->Version.high, header->Version.low); IPRINT ("(GlyphClassDef #x%04X)", header->GlyphClassDef); IPRINT ("(AttachList #x%04X)", header->AttachList); IPRINT ("(LigCaretList #x%04X)", header->LigCaretList); IPRINT ("(MarkAttachClassDef #x%04X))", header->MarkAttachClassDef); } static void dump_attach_list (int indent, OTF_AttachList *list) { } static void dump_lig_caret_list (int indent, OTF_LigCaretList *list) { int i, j; IPRINT ("(LigCaretList"); indent++; free (dump_coverage (indent, NULL, &list->Coverage)); IPRINT ("(LigGlyphCount %d)", list->LigGlyphCount); for (i = 0; i < list->LigGlyphCount; i++) { IPRINT ("(LigGlyph (%d) (offset #x%04X)", i, list->LigGlyph[i].offset); indent++; IPRINT ("(CaretCount %d)", list->LigGlyph[i].CaretCount); for (j = 0; j < list->LigGlyph[i].CaretCount; j++) { unsigned format = list->LigGlyph[i].CaretValue[j].CaretValueFormat; IPRINT ("(Caret (%d) (CaretValueFormat %d)", j, format); if (format == 1) { printf ("(Coordinate %d)", list->LigGlyph[i].CaretValue[j].f.f1.Coordinate); } else if (format == 2) { printf ("(CaretValuePoint %d)", list->LigGlyph[i].CaretValue[j].f.f2.CaretValuePoint); } else if (format == 3) { printf ("(Coodinate %d)", list->LigGlyph[i].CaretValue[j].f.f3.Coordinate); indent++; dump_device_table (indent, "DeviceTable", &list->LigGlyph[i].CaretValue[j].f.f3.DeviceTable); indent--; } printf (")"); } printf (")"); } printf (")"); } static void dump_gdef_table (int indent, OTF_GDEF *gdef) { if (! gdef) return; IPRINT ("(GDEF"); indent++; dump_gdef_header (indent, &gdef->header); if (gdef->header.GlyphClassDef) dump_class_def (indent, "GlyphClassDef", &gdef->glyph_class_def); if (gdef->header.AttachList) dump_attach_list (indent, &gdef->attach_list); if (gdef->header.LigCaretList) dump_lig_caret_list (indent, &gdef->lig_caret_list); if (gdef->header.MarkAttachClassDef) dump_class_def (indent, "MarkAttachClassDef", &gdef->mark_attach_class_def); printf (")"); } /* cmap */ static void dump_cmap_table (int indent, OTF_cmap *cmap) { int i; IPRINT ("(cmap"); indent++; IPRINT ("(version %d)", cmap->version); IPRINT ("(numTables %d)", cmap->numTables); for (i = 0; i < cmap->numTables; i++) { IPRINT ("(EncodingRecord (%d) (platformID %d) (encodingID %d)", i, cmap->EncodingRecord[i].platformID, cmap->EncodingRecord[i].encodingID); indent++; IPRINT ("(Subtable (offset #x%04X) (format %d) (length #x%04X) (language %d)", cmap->EncodingRecord[i].offset, cmap->EncodingRecord[i].subtable.format, cmap->EncodingRecord[i].subtable.length, cmap->EncodingRecord[i].subtable.language); indent++; switch (cmap->EncodingRecord[i].subtable.format) { case 0: { int j, k; unsigned char *array = cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray; IPRINT ("(glyphIdArray"); for (j = 0; j < 16; j++) { IPRINT (" "); for (k = 0; k < 16; k++) printf (" %3d", array[j * 16 + k]); } printf (")"); } break; case 4: { OTF_EncodingSubtable4 *sub4 = cmap->EncodingRecord[i].subtable.f.f4; int j; IPRINT ("(segCountX2 %d) (searchRange %d)", sub4->segCountX2, sub4->searchRange); IPRINT ("(entrySelector %d) (rangeShift %d)", sub4->entrySelector, sub4->rangeShift); for (j = 0; j < sub4->segCountX2 / 2; j++) { IPRINT ("(Segment (%d)", j); indent++; IPRINT ("(startCount #x%04X) (endCount #x%04X)", sub4->segments[j].startCount, sub4->segments[j].endCount); IPRINT ("(idDelta %d) (idRangeOffset #x%04X))", sub4->segments[j].idDelta, sub4->segments[j].idRangeOffset); indent--; } IPRINT ("(glyphIdArray"); for (j = 0; j < sub4->GlyphCount; j++) { if ((j % 16) == 0) IPRINT (" "); printf (" %3d", sub4->glyphIdArray[j]); } printf (")"); } break; case 6: { OTF_EncodingSubtable6 *sub6 = cmap->EncodingRecord[i].subtable.f.f6; int j; IPRINT ("(firstCode %d) (entryCount %d)", sub6->firstCode, sub6->entryCount); IPRINT ("(glyphIdArray"); for (j = 0; j < sub6->entryCount; j++) { if ((j % 16) == 0) IPRINT (" "); printf (" %3d", sub6->glyphIdArray[j]); } printf (")"); } break; case 12: { OTF_EncodingSubtable12 *sub12 = cmap->EncodingRecord[i].subtable.f.f12; int j; for (j = 0; j < sub12->nGroups; j++) { IPRINT ("(Group (#x%X) (startChar #x%04X) (endChar #x%04X) (startGlyphID #x%X))", j, sub12->Groups[j].startCharCode, sub12->Groups[j].endCharCode, sub12->Groups[j].startGlyphID); } } break; case 14: { OTF_EncodingSubtable14 *sub14 = cmap->EncodingRecord[i].subtable.f.f14; unsigned j,k; IPRINT ("(VariationSelectorRecords %d)",sub14->nRecords); for (j = 0; j < sub14->nRecords; j++) { OTF_VariationSelectorRecord *record = sub14->Records + j; IPRINT ("(VariationSelectorRecord (varSelector #x%x)", record->varSelector); indent += 1; IPRINT ("(defaultUVSOffset #x%x)", record->defaultUVSOffset); if (record->defaultUVSOffset) { IPRINT ("(defaultUVS"); indent += 1; for (k = 0 ; k < record->numUnicodeValueRanges; k++) { OTF_UnicodeValueRange *unicodeValueRange = &record->unicodeValueRanges[k]; IPRINT("(startUnicodeValue #x%x) (additionalCount %d)", unicodeValueRange->startUnicodeValue, unicodeValueRange->additionalCount); } printf (")"); indent -= 1; } IPRINT ("(nonDefaultUVSOffset #x%x)", record->nonDefaultUVSOffset); if (record->nonDefaultUVSOffset) { IPRINT ("(NonDefaultUVS"); indent += 1; for (k=0; k < record->numUVSMappings; k++) { OTF_UVSMapping *uvsMapping = &record->uvsMappings[k]; IPRINT("(unicodeValue #x%x) (glyphID %d)", uvsMapping->unicodeValue, uvsMapping->glyphID); } printf (")"); indent -= 1; } printf (")"); indent -= 1; } } } indent -= 2; printf ("))"); } printf (")"); } /* name */ static void dump_name_table (int indent, OTF_name *name) { int i; IPRINT ("(name"); indent++; IPRINT ("(format %d)", name->format); IPRINT ("(count %d)", name->count); IPRINT ("(stringOffset %d)", name->stringOffset); for (i = 0; i < name->count; i++) { OTF_NameRecord *rec = name->nameRecord + i; IPRINT ("(nameRecord (%d)", i); indent++; IPRINT ("(platformID %d) (encodingID %d) (languageID %d) (nameID %d)", rec->platformID, rec->encodingID, rec->languageID, rec->nameID); IPRINT ("(length %d) (offset #x%04X))", rec->length, rec->offset); indent--; } for (i = 0; i <= OTF_max_nameID; i++) if (name->name[i]) IPRINT ("(nameID %d \"%s\")", i, name->name[i]); printf (")"); } static void otf_dump (OTF *otf) { int i; printf ("(OTF"); dump_offset_table (1, &otf->offset_table); for (i = 0; i < otf->offset_table.numTables; i++) dump_table_directory (1, otf->table_dirs + i, i); if (otf->head) dump_head_table (1, otf->head); if (otf->name) dump_name_table (1, otf->name); if (otf->cmap) dump_cmap_table (1, otf->cmap); if (otf->gdef) dump_gdef_table (1, otf->gdef); if (otf->gsub) dump_gsub_table (1, otf->gsub); if (otf->gpos) dump_gpos_table (1, otf->gpos); #if 0 if (otf->base) dump_base_table (1, otf->base); if (otf->jstf) dump_jstf_table (1, otf->jstf); #endif printf (")\n"); } int main (int argc, char **argv) { OTF *otf; if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help")) { fprintf (stderr, "Usage: %s OTF-FILE\n", basename (argv[0])); exit (argc != 2); } otf = OTF_open (argv[1]); if (! otf) { OTF_perror ("otfdump"); exit (1); } OTF_get_table (otf, "head"); OTF_get_table (otf, "name"); OTF_get_table (otf, "cmap"); OTF_get_table (otf, "GDEF"); OTF_get_table (otf, "GSUB"); OTF_get_table (otf, "GPOS"); #if 0 OTF_get_table (otf, "BASE"); OTF_get_table (otf, "JSTF"); #endif otf_dump (otf); OTF_close (otf); exit (0); }