(dump_lookup_subtable_gsub): For Lookup Type
[m17n/libotf.git] / example / otfdump.c
1 /* otfdump.c -- Dump OpenType Layout Tables.
2
3 Copyright (C) 2003, 2004
4   National Institute of Advanced Industrial Science and Technology (AIST)
5   Registration Number H15PRO167
6
7 This file is part of libotf.
8
9 Libotf is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 Libotf is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17 License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library, in a file named COPYING; if not,
21 write to the Free Software Foundation, Inc., 59 Temple Place, Suite
22 330, Boston, MA 02111-1307, USA.  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <libgen.h>
31
32 #include <otf.h>
33
34 char *indent_spaces[] =
35   { "", "  ", "    ", "      ", "        ", "          ", "            ",
36     "              ",  "                ",  "                  " };
37
38 /* Indented print.  */
39 #define IPRINT printf("\n%s", indent_spaces[indent]), printf
40
41 static void
42 dump_tag (OTF_Tag tag)
43 {
44   printf ("(tag \"");
45   putchar (tag >> 24);
46   putchar ((tag >> 16) & 0xFF);
47   putchar ((tag >> 8) & 0xFF);
48   putchar (tag & 0xFF);
49   printf ("\" #x%04X)", tag);
50 }
51
52 /* HEAD */
53
54 static void
55 dump_offset_table (int indent, OTF_OffsetTable *table)
56 {
57   IPRINT ("(OffsetTable");
58   indent++;
59   IPRINT ("(sfnt-version %d.%d)", 
60           table->sfnt_version.high, table->sfnt_version.low);
61   IPRINT ("(numTables %d)", table->numTables);
62   IPRINT ("(searchRange %d)", table->searchRange);
63   IPRINT ("(enterSelector %d)", table->enterSelector);
64   IPRINT ("(rangeShift %d))", table->rangeShift);  
65 }
66
67 static void
68 dump_table_directory (int indent, OTF_TableDirectory *table, int idx)
69 {
70   IPRINT ("(Table %d ", idx);
71   dump_tag (table->tag);
72   indent++;
73   IPRINT ("(checkSum %08X) (offset #x%08X) (length: #x%08X))",
74           table->checkSum, table->offset, table->length);
75 }
76
77 \f
78
79 /* head */
80 static void
81 dump_head_table (int indent, OTF_head *head)
82 {
83   IPRINT ("(head");
84   indent++;
85   IPRINT ("(TableVersionNumber %d.%d)",
86           head->TableVersionNumber.high, head->TableVersionNumber.low);
87   IPRINT ("(fontRevision %d.%d)",
88           head->fontRevision.high, head->fontRevision.low);
89   IPRINT ("(checkSumAdjustment #x%04X)", head->checkSumAdjustment);
90   IPRINT ("(magicNumber #x%04X)", head->magicNumber);
91   IPRINT ("(flags #x%04X)", head->flags);
92   IPRINT ("(unitsPerEm %d)", head->unitsPerEm);
93   printf (")");
94 }
95
96 \f
97 /* COMMON */
98
99 static void
100 dump_glyph_ids (int indent, char *title, OTF_GlyphID *ids, unsigned count)
101 {
102   IPRINT ("(%s (count %d)", title, count);
103   while (count-- > 0)
104     {
105       printf (" #x%04X", *ids);
106       ids++;
107     }
108   printf (")");
109 }
110
111 static int *
112 dump_coverage (int indent, char *title, OTF_Coverage *coverage)
113 {
114   int i;
115   int *char_list;
116
117   IPRINT ("(%sCoverage (CoverageFormat %d)",
118           (title ? title : ""), coverage->CoverageFormat);
119   indent++;
120   if (coverage->CoverageFormat == 1)
121     {
122       dump_glyph_ids (indent, "GlyphArray", coverage->table.GlyphArray,
123                       coverage->Count);
124       char_list = malloc (sizeof (int) * (coverage->Count + 1));
125       for (i = 0; i < coverage->Count; i++)
126         char_list[i] = coverage->table.GlyphArray[i];
127       char_list[i] = -1;
128     }
129   else
130     {
131       int n, c;
132
133       IPRINT ("(RangeCount %d)", coverage->Count);
134       indent++;
135       for (i = n = 0; i < coverage->Count; i++)
136         {
137           IPRINT ("(Range (%d) (Start #x%04X) (End #x%04X)", i,
138                   coverage->table.RangeRecord[i].Start,
139                   coverage->table.RangeRecord[i].End);
140           indent++;
141           IPRINT ("(StartCoverageIndex %d))",
142                   coverage->table.RangeRecord[i].StartCoverageIndex);
143           indent--;
144           n += (coverage->table.RangeRecord[i].End
145                 - coverage->table.RangeRecord[i].Start + 1);
146         }
147       char_list = malloc (sizeof (int) * (n + 1));
148       for (i = n = 0; i < coverage->Count; i++)
149         for (c = coverage->table.RangeRecord[i].Start;
150              c <= coverage->table.RangeRecord[i].End;
151              c++)
152           char_list[n++] = c;
153       char_list[n] = -1;
154     }
155   printf (")");
156   return char_list;
157 }
158
159 static void
160 dump_coverage_list (int indent, char *title,
161                     OTF_Coverage *coverage, unsigned num)
162 {
163   int i;
164
165   IPRINT ("(%s %d)", title, num);
166   for (i = 0; i < num; i++)
167     free (dump_coverage (indent, NULL, coverage + i));
168 }
169
170
171 static void
172 dump_language_system (int indent, int index, OTF_Tag tag, OTF_Offset offset,
173                       OTF_LangSys *langsys)
174 {
175   int i;
176
177   IPRINT ("(LangSys ");
178   if (index >= 0)
179     printf ("(%d) ", index);
180   if (tag)
181     dump_tag (tag);
182   else
183     printf ("DefaultLangSys");
184   printf (" (Offset #x%04X)", offset);
185   indent++;
186   IPRINT ("(LookupOrder #x%04X)", langsys->LookupOrder);
187   IPRINT ("(ReqFeatureIndex %d)", langsys->ReqFeatureIndex);
188   IPRINT ("(FeatureCount %d)", langsys->FeatureCount);
189   if (langsys->FeatureCount)
190     {
191       IPRINT ("(FeatureIndex");
192       for (i = 0; i < langsys->FeatureCount; i++)
193         printf (" %d", langsys->FeatureIndex[i]);
194       printf (")");
195     }
196   printf (")");
197 }
198
199 static void
200 dump_script_list (int indent, OTF_ScriptList *list)
201 {
202   int i, j;
203
204   IPRINT ("(ScriptList (count %d)", list->ScriptCount);
205   indent++;
206   for (i = 0; i < list->ScriptCount; i++)
207     {
208       OTF_Script *script = list->Script + i;
209
210       IPRINT ("(Script (%d) ", i);
211       dump_tag (list->Script[i].ScriptTag);
212       printf (" (Offset #x%04X)", list->Script[i].offset);
213       indent++;
214       IPRINT ("(DefaultLangSysOffset #x%04X)",
215               script->DefaultLangSysOffset);
216       if (script->DefaultLangSysOffset)
217         dump_language_system (indent, -1, 0,
218                               script->DefaultLangSysOffset,
219                               &script->DefaultLangSys);
220       IPRINT ("(LangSysCount %d)", script->LangSysCount);
221       for (j = 0; j < script->LangSysCount; j++)
222         dump_language_system (indent, j,
223                               script->LangSysRecord[j].LangSysTag,
224                               script->LangSysRecord[j].LangSys,
225                               script->LangSys + j);
226       printf (")");
227       indent--;
228     }
229   printf (")");
230 }
231
232 static void
233 dump_feature_list (int indent, OTF_FeatureList *list)
234 {
235   int i, j;
236   
237   IPRINT ("(FeatureList (count %d)", list->FeatureCount);
238   indent++;
239   for (i = 0; i < list->FeatureCount; i++)
240     {
241       OTF_Feature *feature = list->Feature + i;
242
243       IPRINT ("(Feature (%d) ", i);
244       dump_tag (list->Feature[i].FeatureTag);
245       printf (" (Offset #x%04X)", list->Feature[i].offset);
246       printf (" (LookupCount %d)", feature->LookupCount);
247       if (feature->LookupCount)
248         {
249           indent++;
250           IPRINT ("(LookupListIndex");
251           for (j = 0; j < feature->LookupCount; j++)
252             printf (" %d", feature->LookupListIndex[j]);
253           printf (")");
254           indent--;
255         }
256       printf (")");
257     }
258   printf (")");
259 }
260
261 static void
262 dump_class_def (int indent, char *title, OTF_ClassDef *class)
263 {
264   IPRINT ("(%s (offset #x%04X) (ClassFormat %d)",
265           (title ? title : "ClassDef"),
266           class->offset, class->ClassFormat);
267   if (class->offset)
268     {
269       indent++;
270       if (class->ClassFormat == 1)
271         {
272           IPRINT ("(StartGlyph #x%04X)", class->f.f1.StartGlyph);
273           dump_glyph_ids (indent, "ClassValueArray",
274                           (OTF_GlyphID *) class->f.f1.ClassValueArray,
275                           class->f.f1.GlyphCount);
276         }
277       else if (class->ClassFormat == 2)
278         {
279           int i;
280
281           IPRINT ("(ClassRangeCount %d)", class->f.f2.ClassRangeCount);
282           IPRINT ("(ClassRangeRecord");
283           indent++;
284           for (i = 0; i < class->f.f2.ClassRangeCount; i++)
285             IPRINT ("((Start #x%04X) (End #x%04X) (class %d))",
286                     class->f.f2.ClassRangeRecord[i].Start,
287                     class->f.f2.ClassRangeRecord[i].End,
288                     class->f.f2.ClassRangeRecord[i].Class);
289           printf (")");
290         }
291       else
292         printf (" UnknownClassFormat");
293     }
294   printf (")");
295 }
296
297 static void
298 dump_device_table (int indent, char *title, OTF_DeviceTable *table)
299 {
300   int i;
301
302   if (! table->offset)
303     return;
304   IPRINT ("(%s (offset #x%04X)", title, table->offset);
305   indent++;
306   IPRINT ("(StartSize %d) (EndSize %d) (DeltaFormat %d)",
307           table->StartSize, table->EndSize, table->DeltaFormat);
308   IPRINT ("(DeltaValue");
309   for (i = 0; i < table->EndSize - table->StartSize + 1; i++)
310     printf (" %d", table->DeltaValue[i]);
311   printf ("))");
312 }
313
314 \f
315
316 static void
317 dump_value_record (int indent, char *title, OTF_ValueRecord *rec)
318 {
319   IPRINT ("(%s %d %d %d %d", title,
320           rec->XPlacement, rec->YPlacement, rec->XAdvance, rec->YAdvance);
321   indent++;
322   if (rec->XPlaDevice.offset)
323     dump_device_table (indent, "XPlaDevice", &rec->XPlaDevice);
324   if (rec->YPlaDevice.offset)
325     dump_device_table (indent, "YPlaDevice", &rec->YPlaDevice);
326   if (rec->XAdvDevice.offset)
327     dump_device_table (indent, "XAdvDevice", &rec->XAdvDevice);
328   if (rec->YAdvDevice.offset)
329     dump_device_table (indent, "YAdvDevice", &rec->YAdvDevice);
330   printf (")");
331 }
332
333
334 static void
335 dump_sequence_list (int indent, OTF_Sequence *sequence, unsigned num)
336 {
337   int i;
338   IPRINT ("(SequenceCount %d)", num);
339
340   for (i = 0; i < num; i++)
341     {
342       IPRINT ("(Sequence (%d) (offset #x%04X)",
343               i, sequence[i].offset);
344       dump_glyph_ids (indent + 1, "Substitute", sequence[i].Substitute,
345                       sequence[i].GlyphCount);
346       printf (")");
347     }
348 }
349
350 static void
351 dump_alternate_set_list (int indent, OTF_AlternateSet *altset, unsigned num)
352 {
353   int i;
354
355   IPRINT ("(AlternateSetCount %d)", num);
356   for (i = 0; i < num; i++)
357     {
358       IPRINT ("(AlternateSet (%d) (offset #x%04X)",
359               i, altset[i].offset);
360       dump_glyph_ids (indent + 1, "Alternate", altset[i].Alternate,
361                       altset[i].GlyphCount);
362       printf (")");
363     }
364 }
365
366
367 static void
368 dump_ligature_set_list (int indent, int *char_list,
369                         OTF_LigatureSet *ligset, unsigned num)
370 {
371   int i, j, k;
372
373   IPRINT ("(LigSetCount %d)", num);
374   for (i = 0; i < num; i++)
375     {
376       IPRINT ("(LigatureSet (%d) (offset #x%04X) (count %d)",
377               i, ligset[i].offset, ligset[i].LigatureCount);
378       indent++;
379       for (j = 0; j < ligset[i].LigatureCount; j++)
380         {
381           IPRINT ("(Ligature (%d) (offset #x%04X)",
382                   j, ligset[i].Ligature[j].offset);
383           indent++;
384           IPRINT ("(LigGlyph #x%04X)",
385                   ligset[i].Ligature[j].LigGlyph);
386           dump_glyph_ids (indent, "Component", ligset[i].Ligature[j].Component,
387                           ligset[i].Ligature[j].CompCount - 1);
388           IPRINT ("(i.e. #x%04X", char_list[i]);
389           for (k = 0; k < ligset[i].Ligature[j].CompCount - 1; k++)
390             printf (" #x%04X", ligset[i].Ligature[j].Component[k]);
391           printf (" = #x%04X)", ligset[i].Ligature[j].LigGlyph);
392           printf (")");
393           indent--;
394         }
395       indent--;
396       printf (")");
397     }
398 }
399
400 static void
401 dump_pair_set_list (int indent, unsigned count, OTF_PairSet *set)
402 {
403   int i, j;
404
405   for (i = 0; i < count; i++)
406     {
407       IPRINT ("(PairSet (%d)", i);
408       indent++;
409       for (j = 0; j < set[i].PairValueCount; j++)
410         {
411           IPRINT ("(PairValueRecord (%d)", j);
412           indent++;
413           IPRINT ("(SecondGlyph #x%04X)",
414                   set[i].PairValueRecord[j].SecondGlyph);
415           dump_value_record (indent, "Value1",
416                              &set[i].PairValueRecord[j].Value1);
417           dump_value_record (indent, "Value2",
418                              &set[i].PairValueRecord[j].Value2);
419           printf (")");
420           indent--;
421         }
422       printf (")");
423       indent--;
424     }
425 }
426
427 static void
428 dump_class1_record_list (int indent,
429                          unsigned Class1Count, unsigned Class2Count,
430                          OTF_Class1Record *rec)
431 {
432   int i, j;
433
434   for (i = 0; i < Class1Count; i++)
435     {
436       IPRINT ("(Class1Record (%d)", i);
437       indent++;
438       for (j = 0; j < Class2Count; j++)
439         {
440           IPRINT ("(Class2Record (%d)", j);
441           indent++;
442           dump_value_record (indent, "Value1", &rec[i].Class2Record[j].Value1);
443           dump_value_record (indent, "Value2", &rec[i].Class2Record[j].Value2);
444           printf (")");
445           indent--;
446         }
447       printf (")");
448       indent--;
449     }
450 }
451
452 static void
453 dump_anchor (int indent, OTF_Anchor *anchor)
454 {
455   IPRINT ("(Anchor (offset #x%04X) (AnchorFormat %d)",
456           anchor->offset, anchor->AnchorFormat);
457   indent++;
458   IPRINT ("(XCoordinate %d) (YCoordinate %d)",
459           anchor->XCoordinate, anchor->YCoordinate);
460   if (anchor->AnchorFormat == 1)
461     ;
462   else if (anchor->AnchorFormat == 2)
463     IPRINT ("(AnchorPoint %d)", anchor->f.f1.AnchorPoint);
464   else
465     {
466       dump_device_table (indent, "XDeviceTable", &anchor->f.f2.XDeviceTable);
467       dump_device_table (indent, "YDeviceTable", &anchor->f.f2.YDeviceTable);
468     }
469   printf (")");
470 }
471
472 static void
473 dump_entry_exit_list (int indent, unsigned count, OTF_EntryExitRecord *rec)
474 {
475   int i;
476
477   for (i = 0; i < count; i++)
478     {
479       IPRINT ("(EntryExitRecord (%d)", i);
480       indent++;
481       dump_anchor (indent, &rec[i].EntryAnchor);
482       dump_anchor (indent, &rec[i].EntryAnchor);
483       printf (")");
484       indent--;
485     }
486 }
487
488 static void
489 dump_mark_array (int indent, OTF_MarkArray *array)
490 {
491   int i;
492
493   IPRINT ("(MarkArray (MarkCount %d)", array->MarkCount);
494   indent++;
495   for (i = 0; i < array->MarkCount; i++)
496     {
497       IPRINT ("(MarkRecord (%d) (Class %d)", i, array->MarkRecord[i].Class);
498       dump_anchor (indent + 1, &array->MarkRecord[i].MarkAnchor);
499       printf (")");
500     }
501   printf (")");
502 }
503
504 static void
505 dump_anchor_array (int indent, unsigned ClassCount, OTF_AnchorArray *array)
506 {
507   int i, j;
508
509   IPRINT ("(AnchorArray (Count %d)", array->Count);
510   indent++;
511   for (i = 0; i < array->Count; i++)
512     {
513       IPRINT ("(AnchorRecord (%d) ", i);
514       for (j = 0; j < ClassCount; j++)
515         dump_anchor (indent + 1, array->AnchorRecord[i].Anchor + j);
516       printf (")");
517     }
518   printf (")");
519 }
520
521
522 static void
523 dump_lookup_record_list (int indent, OTF_LookupRecord *rec, unsigned num)
524 {
525   int i;
526
527   IPRINT ("(LookupCount %d)", num);
528   for (i = 0; i < num; i++)
529     {
530       IPRINT ("(LookupRecord (%d)", i);
531       indent++;
532       IPRINT ("(SequenceIndex %d)", rec[i].SequenceIndex);
533       IPRINT ("(LookupListIndex %d))", rec[i].LookupListIndex);
534       indent--;
535     }
536 }
537
538
539 static void dump_lookup_subtable_gsub (int indent, int index, unsigned type,
540                                        OTF_LookupSubTableGSUB *subtable);
541 static void dump_lookup_subtable_gpos (int indent, int index, unsigned type,
542                                        OTF_LookupSubTableGPOS *subtable);
543
544
545 static void
546 dump_lookup_list (int indent, OTF_LookupList *list, int gsub)
547 {
548   int i, j;
549
550   IPRINT ("(LookupList (count %d)", list->LookupCount);
551   indent++;
552   for (i = 0; i < list->LookupCount; i++)
553     {
554       OTF_Lookup *lookup = list->Lookup + i;
555
556       IPRINT ("(Lookup (%d) (Offset #x%04X)",
557               i, lookup->offset);
558       printf (" (Type %d) (Flag #x%04X) (SubTableCount %d)",
559               lookup->LookupType, lookup->LookupFlag, lookup->SubTableCount);
560       if (gsub)
561         for (j = 0; j < lookup->SubTableCount; j++)
562           dump_lookup_subtable_gsub (indent + 1, j,
563                                      lookup->LookupType,
564                                      lookup->SubTable.gsub + j);
565       else
566         for (j = 0; j < lookup->SubTableCount; j++)
567           dump_lookup_subtable_gpos (indent + 1, j,
568                                      lookup->LookupType,
569                                      lookup->SubTable.gpos + j);
570
571       printf (")");
572     }
573   printf (")");
574 }
575
576 static void
577 dump_rule_list (int indent, OTF_Rule *rule, int count)
578 {
579   int i;
580
581   IPRINT ("(RuleCount %d)", count);
582   for (i = 0; i < count; i++)
583     {
584       IPRINT ("(Rule (%d)", i);
585       indent++;
586       IPRINT ("(GlyphCount %d)", rule[i].GlyphCount);
587       IPRINT ("(LookupCount %d)", rule[i].LookupCount);
588       dump_glyph_ids (indent, "Input", rule[i].Input, rule[i].GlyphCount - 1);
589       dump_lookup_record_list (indent, rule[i].LookupRecord,
590                                rule[i].LookupCount);
591       printf (")");
592       indent--;
593     }
594 }
595
596 static void
597 dump_rule_set_list (int indent, OTF_RuleSet *set, int count)
598 {
599   int i;
600
601   IPRINT ("(RuleSetCount %d)", count);
602   for (i = 0; i < count; i++)
603     {
604       IPRINT ("(RuleSet (%d)", i);
605       dump_rule_list (indent + 1, set[i].Rule, set[i].RuleCount);
606       printf (")");
607     }
608 }
609
610 static void
611 dump_class_rule_list (int indent, OTF_ClassRule *rule, int count)
612 {
613   int i, j;
614
615   IPRINT ("(ClassRuleCnt %d)", count);
616   for (i = 0; i < count; i++)
617     {
618       IPRINT ("(ClassRule (%d)", i);
619       indent++;
620       IPRINT ("(GlyphCount %d)", rule[i].GlyphCount);
621       IPRINT ("(LookupCount %d)", rule[i].LookupCount);
622       IPRINT ("(Class");
623       for (j = 0; j < rule[i].GlyphCount - 1; j++)
624         printf (" %d", rule[i].Class[j]);
625       printf (")");
626       dump_lookup_record_list (indent, rule[i].LookupRecord,
627                                rule[i].LookupCount);
628       printf (")");
629       indent--;
630     }
631 }
632
633 static void
634 dump_class_set_list (int indent, OTF_ClassSet *set, int count)
635 {
636   int i;
637
638   IPRINT ("(ClassSetCount %d)", count);
639   for (i = 0; i < count; i++)
640     if (set[i].offset)
641       {
642         IPRINT ("(ClassSet (%d)", i);
643         dump_class_rule_list (indent + 1, set[i].ClassRule,
644                               set[i].ClassRuleCnt);
645         printf (")");
646       }
647 }
648
649 static void
650 dump_chain_rule_list (int indent, OTF_ChainRule *rule, int count)
651 {
652   int i;
653
654   IPRINT ("(ChainRuleCount %d)", count);
655   for (i = 0; i < count; i++)
656     {
657       IPRINT ("(ChainRule (%d)", i);
658       dump_glyph_ids (indent + 1, "Backtrack",
659                       rule[i].Backtrack, rule[i].BacktrackGlyphCount);
660       dump_glyph_ids (indent + 1, "Input",
661                       rule[i].Input, rule[i].InputGlyphCount - 1);
662       dump_glyph_ids (indent + 1, "LookAhead",
663                       rule[i].LookAhead, rule[i].LookaheadGlyphCount);
664       dump_lookup_record_list (indent + 1, rule[i].LookupRecord,
665                                rule[i].LookupCount);
666       printf (")");
667     }
668 }
669
670 static void
671 dump_chain_rule_set_list (int indent, OTF_ChainRuleSet *set, int count)
672 {
673   int i;
674
675   IPRINT ("(ChainRuleSetCount %d)", count);
676   for (i = 0; i < count; i++)
677     {
678       IPRINT ("(ChainRuleSet (%d)", i);
679       dump_chain_rule_list (indent + 1,
680                             set[i].ChainRule, set[i].ChainRuleCount);
681       printf (")");
682     }
683 }
684
685 static void
686 dump_chain_class_rule_list (int indent, OTF_ChainClassRule *rule, int count)
687 {
688   int i;
689
690   IPRINT ("(ChainClassRuleCount %d)", count);
691   for (i = 0; i < count; i++)
692     {
693       IPRINT ("(ChainClassRule (%d)", i);
694       dump_glyph_ids (indent + 1, "Backtrack",
695                       rule[i].Backtrack, rule[i].BacktrackGlyphCount);
696       dump_glyph_ids (indent + 1, "Input",
697                       rule[i].Input, rule[i].InputGlyphCount - 1);
698       dump_glyph_ids (indent + 1, "LookAhead",
699                       rule[i].LookAhead, rule[i].LookaheadGlyphCount);
700       dump_lookup_record_list (indent + 1, rule[i].LookupRecord,
701                                rule[i].LookupCount);
702       printf (")");
703     }
704 }
705
706 static void
707 dump_chain_class_set_list (int indent, OTF_ChainClassSet *set, int count)
708 {
709   int i;
710
711   IPRINT ("(ChainClassSetCount %d)", count);
712   for (i = 0; i < count; i++)
713     {
714       IPRINT ("(ChainClassSet (%d)", i);
715       dump_chain_class_rule_list (indent + 1,
716                                   set[i].ChainClassRule,
717                                   set[i].ChainClassRuleCnt);
718       printf (")");
719     }
720 }
721
722
723
724
725 \f
726 /* GSUB */
727
728 static void
729 dump_lookup_subtable_gsub (int indent, int index, unsigned type,
730                            OTF_LookupSubTableGSUB *subtable)
731 {
732   IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format);
733   indent++;
734   switch (type)
735     {
736     case 1:
737       if (subtable->Format == 1)
738         {
739           free (dump_coverage (indent, NULL, &subtable->Coverage));
740           IPRINT ("(DeltaGlyhpID #x%04X)",
741                   subtable->u.single1.DeltaGlyphID);
742         }
743       else if (subtable->Format == 2)
744         {
745           free (dump_coverage (indent, NULL, &subtable->Coverage));
746           dump_glyph_ids (indent, "Substitute", subtable->u.single2.Substitute,
747                           subtable->u.single2.GlyphCount);
748         }
749       else
750         printf (" invalid");
751       break;
752
753     case 2:
754       if (subtable->Format == 1)
755         {
756           free (dump_coverage (indent, NULL, &subtable->Coverage));
757           dump_sequence_list (indent,
758                               subtable->u.multiple1.Sequence,
759                               subtable->u.multiple1.SequenceCount);
760         }
761       else
762         printf (" invalid");
763       break;
764       
765     case 3:
766       if (subtable->Format == 1)
767         {
768           free (dump_coverage (indent, NULL, &subtable->Coverage));
769           dump_alternate_set_list (indent, subtable->u.alternate1.AlternateSet,
770                                    subtable->u.alternate1.AlternateSetCount);
771         }
772       else
773         printf (" invalid");
774       break;
775
776     case 4:
777       if (subtable->Format == 1)
778         {
779           int *char_list = dump_coverage (indent, NULL, &subtable->Coverage);
780           dump_ligature_set_list (indent, char_list,
781                                   subtable->u.ligature1.LigatureSet,
782                                   subtable->u.ligature1.LigSetCount);
783           free (char_list);
784         }
785       else
786         printf (" invalid");
787       break;
788
789     case 5:
790       if (subtable->Format == 1)
791         {
792           free (dump_coverage (indent, NULL, &subtable->Coverage));
793           dump_rule_set_list (indent, subtable->u.context1.RuleSet,
794                               subtable->u.context1.RuleSetCount); 
795         }
796       else if (subtable->Format == 2)
797         {
798           free (dump_coverage (indent, NULL, &subtable->Coverage));
799           dump_class_def (indent, NULL, &subtable->u.context2.ClassDef);
800           dump_class_set_list (indent, subtable->u.context2.ClassSet,
801                                subtable->u.context2.ClassSetCnt);
802         }
803       else if (subtable->Format == 3)
804         {
805           dump_coverage_list (indent, "Coverage",
806                               subtable->u.context3.Coverage,
807                               subtable->u.context3.GlyphCount);
808           dump_lookup_record_list (indent,
809                                    subtable->u.context3.LookupRecord,
810                                    subtable->u.context3.LookupCount);
811         }
812       else
813         printf (" invalid");
814       break;
815
816     case 6:
817       if (subtable->Format == 1)
818         {
819           free (dump_coverage (indent, NULL, &subtable->Coverage));
820           dump_chain_rule_set_list
821             (indent,
822              subtable->u.chain_context1.ChainRuleSet,
823              subtable->u.chain_context1.ChainRuleSetCount);
824         }
825       else if (subtable->Format == 2)
826         {
827           free (dump_coverage (indent, NULL, &subtable->Coverage));
828           dump_class_def (indent, "BacktrackClassDef",
829                           &subtable->u.chain_context2.BacktrackClassDef);
830           dump_class_def (indent, "InputClassDef",
831                           &subtable->u.chain_context2.InputClassDef);
832           dump_class_def (indent, "LookaheadClassDef",
833                           &subtable->u.chain_context2.LookaheadClassDef);
834           dump_chain_class_set_list
835             (indent,
836              subtable->u.chain_context2.ChainClassSet,
837              subtable->u.chain_context2.ChainClassSetCnt);
838         }
839       else if (subtable->Format == 3)
840         {
841           dump_coverage_list
842             (indent, "BackTrackGlyphCount",
843              subtable->u.chain_context3.Backtrack,
844              subtable->u.chain_context3.BacktrackGlyphCount);
845           dump_coverage_list
846             (indent, "InputGlyphCount",
847              subtable->u.chain_context3.Input,
848              subtable->u.chain_context3.InputGlyphCount);
849           dump_coverage_list
850             (indent, "LookaheadGlyphCount",
851              subtable->u.chain_context3.LookAhead,
852              subtable->u.chain_context3.LookaheadGlyphCount);
853           dump_lookup_record_list
854             (indent,
855              subtable->u.chain_context3.LookupRecord,
856              subtable->u.chain_context3.LookupCount);
857         }
858       else
859         printf (" invalid");
860       break;
861
862     case 7:
863       IPRINT ("(ExtensionLookupType %d)",
864               subtable->u.extension1.ExtensionLookupType);
865       IPRINT ("(ExtensionOffset %d)",
866               subtable->u.extension1.ExtensionOffset);
867       dump_lookup_subtable_gsub (indent, index, 
868                                  subtable->u.extension1.ExtensionLookupType,
869                                  subtable->u.extension1.ExtensionSubtable);
870       break;
871
872     case 8:
873       printf (" not-yet-supported");
874       break;
875
876     default:
877       printf (" invalid");
878     }
879   printf (")");
880 }
881
882 static void
883 dump_gsub_table (int indent, OTF_GSUB *gsub)
884 {
885   IPRINT ("(GSUB");
886   indent++;
887   IPRINT ("(Header");
888   indent++;
889   IPRINT ("(Version %d.%d)", gsub->Version.high, gsub->Version.low);
890   IPRINT ("(ScriptList #x%04X)", gsub->ScriptList.offset);
891   IPRINT ("(FeatureList #x%04X)", gsub->FeatureList.offset);
892   IPRINT ("(LookupList #x%04X))", gsub->LookupList.offset);
893   indent--;
894   dump_script_list (indent, &gsub->ScriptList);
895   dump_feature_list (indent, &gsub->FeatureList);
896   dump_lookup_list (indent, &gsub->LookupList, 1);
897   printf (")");
898 }
899
900 \f
901 /* GPOS */
902
903 static void
904 dump_lookup_subtable_gpos (int indent, int index, unsigned type,
905                            OTF_LookupSubTableGPOS *subtable)
906 {
907   IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format);
908   indent++;
909   switch (type)
910     {
911     case 1:
912       if (subtable->Format == 1)
913         {
914           free (dump_coverage (indent, NULL, &subtable->Coverage));
915           IPRINT ("(ValueFormat #x%04X)",
916                   subtable->u.single1.ValueFormat);
917           dump_value_record (indent, "Value", &subtable->u.single1.Value);
918         }
919       else if (subtable->Format == 2)
920         {
921           int i;
922
923           free (dump_coverage (indent, NULL, &subtable->Coverage));
924           IPRINT ("(ValueFormat #x%04X)",
925                   subtable->u.single2.ValueFormat);
926           IPRINT ("(ValueCount %d)",
927                   subtable->u.single2.ValueCount);
928           for (i = 0; i < subtable->u.single2.ValueCount; i++)
929             dump_value_record (indent, "Value", &subtable->u.single2.Value[i]);
930         }
931       else
932         printf (" invalid");
933       break;
934
935     case 2:
936       if (subtable->Format == 1)
937         {
938           free (dump_coverage (indent, NULL, &subtable->Coverage));
939           IPRINT ("(ValueFormat1 #x%04X)",
940                   subtable->u.pair1.ValueFormat1);
941           IPRINT ("(ValueFormat2 #x%04X)",
942                   subtable->u.pair1.ValueFormat2);
943           dump_pair_set_list (indent, subtable->u.pair1.PairSetCount,
944                               subtable->u.pair1.PairSet);
945         }
946       else if (subtable->Format == 2)
947         {
948           free (dump_coverage (indent, NULL, &subtable->Coverage));
949           IPRINT ("(ValueFormat1 #x%04X)",
950                   subtable->u.pair2.ValueFormat1);
951           IPRINT ("(ValueFormat2 #x%04X)",
952                   subtable->u.pair2.ValueFormat2);
953           dump_class_def (indent, "ClassDef1",
954                           &subtable->u.pair2.ClassDef1);
955           dump_class_def (indent, "ClassDef2",
956                           &subtable->u.pair2.ClassDef2);
957           IPRINT ("(Class1Count %d)",
958                   subtable->u.pair2.Class1Count);
959           IPRINT ("(Class2Count %d)",
960                   subtable->u.pair2.Class2Count);
961           dump_class1_record_list (indent,
962                                    subtable->u.pair2.Class1Count,
963                                    subtable->u.pair2.Class2Count,
964                                    subtable->u.pair2.Class1Record);
965         }
966       else
967         printf (" invalid");
968       break;
969       
970     case 3:
971       if (subtable->Format == 1)
972         {
973           free (dump_coverage (indent, NULL, &subtable->Coverage));
974           dump_entry_exit_list (indent, subtable->u.cursive1.EntryExitCount,
975                                 subtable->u.cursive1.EntryExitRecord);
976         }
977       else
978         printf (" invalid");
979       break;
980
981     case 4:
982       if (subtable->Format == 1)
983         {
984           free (dump_coverage (indent, "Mark", &subtable->Coverage));
985           free (dump_coverage (indent, "Base",
986                                &subtable->u.mark_base1.BaseCoverage));
987           IPRINT ("(ClassCount %d)",
988                   subtable->u.mark_base1.ClassCount);
989           dump_mark_array (indent, &subtable->u.mark_base1.MarkArray);
990           dump_anchor_array (indent, subtable->u.mark_base1.ClassCount,
991                            &subtable->u.mark_base1.BaseArray);
992         }
993       break;
994
995     case 5:
996       if (subtable->Format == 1)
997         {
998           printf (" not-yet-supported");
999         }
1000       else
1001         printf (" invalid");
1002       break;
1003
1004     case 6:
1005       if (subtable->Format == 1)
1006         {
1007           free (dump_coverage (indent, "Mark1", &subtable->Coverage));
1008           free (dump_coverage (indent, "Mark2",
1009                                &subtable->u.mark_mark1.Mark2Coverage));
1010           IPRINT ("(ClassCount %d)",
1011                   subtable->u.mark_mark1.ClassCount);
1012           dump_mark_array (indent, &subtable->u.mark_mark1.Mark1Array);
1013           dump_anchor_array (indent, subtable->u.mark_mark1.ClassCount,
1014                            &subtable->u.mark_mark1.Mark2Array);
1015         }
1016       else
1017         printf (" invalid");
1018       break;
1019
1020     case 7:
1021       if (subtable->Format == 1)
1022         {
1023           free (dump_coverage (indent, NULL, &subtable->Coverage));
1024           dump_rule_set_list (indent, subtable->u.context1.RuleSet,
1025                               subtable->u.context1.RuleSetCount); 
1026         }
1027       else if (subtable->Format == 2)
1028         {
1029           free (dump_coverage (indent, NULL, &subtable->Coverage));
1030           dump_class_def (indent, NULL, &subtable->u.context2.ClassDef);
1031           dump_class_set_list (indent, subtable->u.context2.ClassSet,
1032                                subtable->u.context2.ClassSetCnt);
1033         }
1034       else if (subtable->Format == 3)
1035         {
1036           dump_coverage_list (indent, "Coverage",
1037                               subtable->u.context3.Coverage,
1038                               subtable->u.context3.GlyphCount);
1039           dump_lookup_record_list (indent,
1040                                    subtable->u.context3.LookupRecord,
1041                                    subtable->u.context3.LookupCount);
1042         }
1043       else
1044         printf (" invalid");
1045       break;
1046
1047     case 8:
1048       if (subtable->Format == 1)
1049         {
1050           free (dump_coverage (indent, NULL, &subtable->Coverage));
1051           dump_chain_rule_set_list
1052             (indent,
1053              subtable->u.chain_context1.ChainRuleSet,
1054              subtable->u.chain_context1.ChainRuleSetCount);
1055         }
1056       else if (subtable->Format == 2)
1057         {
1058           free (dump_coverage (indent, NULL, &subtable->Coverage));
1059           dump_class_def (indent, "BacktrackClassDef",
1060                           &subtable->u.chain_context2.BacktrackClassDef);
1061           dump_class_def (indent, "InputClassDef",
1062                           &subtable->u.chain_context2.InputClassDef);
1063           dump_class_def (indent, "LookaheadClassDef",
1064                           &subtable->u.chain_context2.LookaheadClassDef);
1065           dump_chain_class_set_list
1066             (indent,
1067              subtable->u.chain_context2.ChainClassSet,
1068              subtable->u.chain_context2.ChainClassSetCnt);
1069         }
1070       else if (subtable->Format == 3)
1071         {
1072           dump_coverage_list
1073             (indent, "BackTrackGlyphCount",
1074              subtable->u.chain_context3.Backtrack,
1075              subtable->u.chain_context3.BacktrackGlyphCount);
1076           dump_coverage_list
1077             (indent, "InputGlyphCount",
1078              subtable->u.chain_context3.Input,
1079              subtable->u.chain_context3.InputGlyphCount);
1080           dump_coverage_list
1081             (indent, "LookaheaGlyphCount",
1082              subtable->u.chain_context3.LookAhead,
1083              subtable->u.chain_context3.LookaheadGlyphCount);
1084           dump_lookup_record_list
1085             (indent,
1086              subtable->u.chain_context3.LookupRecord,
1087              subtable->u.chain_context3.LookupCount);
1088         }
1089       else
1090         printf (" invalid");
1091       break;
1092
1093     case 9:
1094       if (subtable->Format == 1)
1095         {
1096           IPRINT ("(ExtensionLookupType %d)",
1097                   subtable->u.extension1.ExtensionLookupType);
1098           IPRINT ("(ExtensionOffset %d)",
1099                   subtable->u.extension1.ExtensionOffset);
1100           dump_lookup_subtable_gpos
1101             (indent, index, 
1102              subtable->u.extension1.ExtensionLookupType,
1103              subtable->u.extension1.ExtensionSubtable);
1104         }
1105       else
1106         printf (" invalid");
1107     }
1108   printf (")");
1109 }
1110
1111
1112 static void
1113 dump_gpos_table (int indent, OTF_GPOS *gpos)
1114 {
1115   if (! gpos)
1116     return;
1117   IPRINT ("(GPOS");
1118   indent++;
1119   IPRINT ("(Header");
1120   indent++;
1121   IPRINT ("(Version %d.%d)", gpos->Version.high, gpos->Version.low);
1122   IPRINT ("(ScriptList #x%04X)", gpos->ScriptList.offset);
1123   IPRINT ("(FeatureList #x%04X)", gpos->FeatureList.offset);
1124   IPRINT ("(LookupList #x%04X))", gpos->LookupList.offset);
1125   indent--;
1126   dump_script_list (indent, &gpos->ScriptList);
1127   dump_feature_list (indent, &gpos->FeatureList);
1128   dump_lookup_list (indent, &gpos->LookupList, 0);
1129   printf (")");
1130 }
1131
1132 #if 0
1133 static void
1134 dump_base_table (OTF_BASE *base)
1135 {
1136 }
1137
1138 static void
1139 dump_jstf_table (OTF_JSTF *jstf)
1140 {
1141 }
1142 #endif
1143
1144 \f
1145 /* GDEF */
1146 static void
1147 dump_gdef_header (int indent, OTF_GDEFHeader *header)
1148 {
1149   IPRINT ("(Header");
1150   indent++;
1151   IPRINT ("(Version %d.%d)",
1152           header->Version.high, header->Version.low);
1153   IPRINT ("(GlyphClassDef #x%04X)", header->GlyphClassDef);
1154   IPRINT ("(AttachList #x%04X)", header->AttachList);
1155   IPRINT ("(LigCaretList #x%04X)", header->LigCaretList);
1156   IPRINT ("(MarkAttachClassDef #x%04X))",
1157           header->MarkAttachClassDef);
1158 }
1159
1160 static void
1161 dump_attach_list (int indent, OTF_AttachList *list)
1162 {
1163 }
1164
1165 static void
1166 dump_lig_caret_list (int indent, OTF_LigCaretList *list)
1167 {
1168   int i, j;
1169
1170   IPRINT ("(LigCaretList");
1171   indent++;
1172   free (dump_coverage (indent, NULL, &list->Coverage));
1173   IPRINT ("(LigGlyphCount %d)", list->LigGlyphCount);
1174   for (i = 0; i < list->LigGlyphCount; i++)
1175     {
1176       IPRINT ("(LigGlyph (%d) (offset #x%04X)",
1177               i, list->LigGlyph[i].offset);
1178       indent++;
1179       IPRINT ("(CaretCount %d)", list->LigGlyph[i].CaretCount);
1180       for (j = 0; j < list->LigGlyph[i].CaretCount; j++)
1181         {
1182           unsigned format = list->LigGlyph[i].CaretValue[j].CaretValueFormat;
1183
1184           IPRINT ("(Caret (%d) (CaretValueFormat %d)", j, format);
1185           if (format == 1)
1186             {
1187               printf ("(Coordinate %d)",
1188                       list->LigGlyph[i].CaretValue[j].f.f1.Coordinate);
1189             }
1190           else if (format == 2)
1191             {
1192               printf ("(CaretValuePoint %d)",
1193                       list->LigGlyph[i].CaretValue[j].f.f2.CaretValuePoint);
1194             }
1195           else if (format == 3)
1196             {
1197               printf ("(Coodinate %d)",
1198                       list->LigGlyph[i].CaretValue[j].f.f3.Coordinate);
1199               indent++;
1200               dump_device_table
1201                 (indent, "DeviceTable", 
1202                  &list->LigGlyph[i].CaretValue[j].f.f3.DeviceTable);
1203               indent--;
1204             }
1205           printf (")");
1206         }
1207       printf (")");
1208     }
1209   printf (")");
1210 }
1211
1212
1213 static void
1214 dump_gdef_table (int indent, OTF_GDEF *gdef)
1215 {
1216   if (! gdef)
1217     return;
1218   IPRINT ("(GDEF");
1219   indent++;
1220   dump_gdef_header (indent, &gdef->header);
1221   if (gdef->header.GlyphClassDef)
1222     dump_class_def (indent, "GlyphClassDef", &gdef->glyph_class_def);
1223   if (gdef->header.AttachList)
1224     dump_attach_list (indent, &gdef->attach_list);
1225   if (gdef->header.LigCaretList)
1226     dump_lig_caret_list (indent, &gdef->lig_caret_list);
1227   if (gdef->header.MarkAttachClassDef)
1228     dump_class_def (indent, "MarkAttachClassDef",
1229                     &gdef->mark_attach_class_def);
1230   printf (")");
1231 }
1232
1233 \f
1234 /* cmap */
1235 static void
1236 dump_cmap_table (int indent, OTF_cmap *cmap)
1237 {
1238   int i;
1239
1240   IPRINT ("(cmap");
1241   indent++;
1242   IPRINT ("(version %d)", cmap->version);
1243   IPRINT ("(numTables %d)", cmap->numTables);
1244   for (i = 0; i < cmap->numTables; i++)
1245     {
1246       IPRINT ("(EncodingRecord (%d) (platformID %d) (encodingID %d)",
1247               i,
1248               cmap->EncodingRecord[i].platformID,
1249               cmap->EncodingRecord[i].encodingID);
1250       indent++;
1251       IPRINT ("(Subtable (offset #x%04X) (format %d) (length #x%04X) (language %d)",
1252               cmap->EncodingRecord[i].offset,
1253               cmap->EncodingRecord[i].subtable.format,
1254               cmap->EncodingRecord[i].subtable.length,
1255               cmap->EncodingRecord[i].subtable.language);
1256       indent++;
1257       switch (cmap->EncodingRecord[i].subtable.format)
1258         {
1259         case 0:
1260           {
1261             int j, k;
1262             unsigned char *array
1263               = cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray;
1264
1265             IPRINT ("(glyphIdArray");
1266             for (j = 0; j < 16; j++)
1267               {
1268                 IPRINT (" ");
1269                 for (k = 0; k < 16; k++)
1270                   printf (" %3d", array[j * 16 + k]);
1271               }
1272             printf (")");
1273           }
1274           break;
1275
1276         case 4:
1277           {
1278             OTF_EncodingSubtable4 *sub4
1279               = cmap->EncodingRecord[i].subtable.f.f4;
1280             int j;
1281
1282             IPRINT ("(segCountX2 %d) (searchRange %d)",
1283                     sub4->segCountX2, sub4->searchRange);
1284             IPRINT ("(entrySelector %d) (rangeShift %d)",
1285                     sub4->entrySelector, sub4->rangeShift);
1286             for (j = 0; j < sub4->segCountX2 / 2; j++)
1287               {
1288                 IPRINT ("(Segment (%d)", j);
1289                 indent++;
1290                 IPRINT ("(startCount #x%04X) (endCount #x%04X)",
1291                         sub4->segments[j].startCount,
1292                         sub4->segments[j].endCount);
1293                 IPRINT ("(idDelta %d) (idRangeOffset #x%04X))",
1294                         sub4->segments[j].idDelta,
1295                         sub4->segments[j].idRangeOffset);
1296                 indent--;
1297               }
1298             IPRINT ("(glyphIdArray");
1299             for (j = 0; j < sub4->GlyphCount; j++)
1300               {
1301                 if ((j % 16) == 0)
1302                   IPRINT (" ");
1303                 printf (" %3d", sub4->glyphIdArray[j]);
1304               }
1305             printf (")");
1306           }
1307           break;
1308
1309         case 6:
1310           {
1311             OTF_EncodingSubtable6 *sub6
1312               = cmap->EncodingRecord[i].subtable.f.f6;
1313             int j;
1314
1315             IPRINT ("(firstCode %d) (entryCount %d)",
1316                     sub6->firstCode, sub6->entryCount);
1317             IPRINT ("(glyphIdArray");
1318             for (j = 0; j < sub6->entryCount; j++)
1319               {
1320                 if ((j % 16) == 0)
1321                   IPRINT (" ");
1322                 printf (" %3d", sub6->glyphIdArray[j]);
1323               }
1324             printf (")");
1325           }
1326           break;
1327         }
1328
1329       indent -= 2;
1330       printf ("))");
1331     }
1332   printf (")");
1333 }
1334 \f
1335
1336 /* name */
1337 static void
1338 dump_name_table (int indent, OTF_name *name)
1339 {
1340   int i;
1341
1342   IPRINT ("(name");
1343   indent++;
1344   IPRINT ("(format %d)", name->format);
1345   IPRINT ("(count %d)", name->count);
1346   IPRINT ("(stringOffset %d)", name->stringOffset);
1347   for (i = 0; i < name->count; i++)
1348     {
1349       OTF_NameRecord *rec = name->nameRecord + i; 
1350
1351       IPRINT ("(nameRecord (%d)", i);
1352       indent++;
1353       IPRINT ("(platformID %d) (encodingID %d) (languageID %d) (nameID %d)",
1354               rec->platformID, rec->encodingID, rec->languageID, rec->nameID);
1355       IPRINT ("(length %d) (offset #x%04X))", rec->length, rec->offset);
1356       indent--;
1357     }
1358   for (i = 0; i <= OTF_max_nameID; i++)
1359     if (name->name[i])
1360       IPRINT ("(nameID %d \"%s\")", i, name->name[i]);
1361
1362   printf (")");
1363 }
1364
1365 \f
1366
1367 static void
1368 otf_dump (OTF *otf)
1369 {
1370   int i;
1371
1372   printf ("(OTF");
1373
1374   dump_offset_table (1, &otf->offset_table);
1375   for (i = 0; i < otf->offset_table.numTables; i++)
1376     dump_table_directory (1, otf->table_dirs + i, i);
1377
1378   if (otf->head)
1379     dump_head_table (1, otf->head);
1380   if (otf->name)
1381     dump_name_table (1, otf->name);
1382   if (otf->cmap)
1383     dump_cmap_table (1, otf->cmap);
1384   if (otf->gdef)
1385     dump_gdef_table (1, otf->gdef);
1386   if (otf->gsub)
1387     dump_gsub_table (1, otf->gsub);
1388   if (otf->gpos)
1389     dump_gpos_table (1, otf->gpos);
1390 #if 0
1391   if (otf->base)
1392     dump_base_table (1, otf->base);
1393   if (otf->jstf)
1394     dump_jstf_table (1, otf->jstf);
1395 #endif
1396   printf (")\n");
1397 }
1398
1399
1400 int
1401 main (int argc, char **argv)
1402 {
1403   OTF *otf;
1404
1405   if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1406     {
1407       fprintf (stderr, "Usage: %s OTF-FILE\n", basename (argv[0]));
1408       exit (argc != 2);
1409     }
1410   
1411   otf = OTF_open (argv[1]);
1412   if (! otf)
1413     {
1414       OTF_perror ("otfdump");
1415       exit (1);
1416     }
1417   OTF_get_table (otf, "head");
1418   OTF_get_table (otf, "name");
1419   OTF_get_table (otf, "cmap");
1420   OTF_get_table (otf, "GDEF");
1421   OTF_get_table (otf, "GSUB");
1422   OTF_get_table (otf, "GPOS");
1423 #if 0
1424   OTF_get_table (otf, "BASE");
1425   OTF_get_table (otf, "JSTF");
1426 #endif
1427   otf_dump (otf);
1428   OTF_close (otf);
1429   exit (0);
1430 }