*** empty log message ***
[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
870                                   + subtable->u.extension1.ExtensionOffset));
871       break;
872
873     case 8:
874       printf (" not-yet-supported");
875       break;
876
877     default:
878       printf (" invalid");
879     }
880   printf (")");
881 }
882
883 static void
884 dump_gsub_table (int indent, OTF_GSUB *gsub)
885 {
886   IPRINT ("(GSUB");
887   indent++;
888   IPRINT ("(Header");
889   indent++;
890   IPRINT ("(Version %d.%d)", gsub->Version.high, gsub->Version.low);
891   IPRINT ("(ScriptList #x%04X)", gsub->ScriptList.offset);
892   IPRINT ("(FeatureList #x%04X)", gsub->FeatureList.offset);
893   IPRINT ("(LookupList #x%04X))", gsub->LookupList.offset);
894   indent--;
895   dump_script_list (indent, &gsub->ScriptList);
896   dump_feature_list (indent, &gsub->FeatureList);
897   dump_lookup_list (indent, &gsub->LookupList, 1);
898   printf (")");
899 }
900
901 \f
902 /* GPOS */
903
904 static void
905 dump_lookup_subtable_gpos (int indent, int index, unsigned type,
906                            OTF_LookupSubTableGPOS *subtable)
907 {
908   IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format);
909   indent++;
910   switch (type)
911     {
912     case 1:
913       if (subtable->Format == 1)
914         {
915           free (dump_coverage (indent, NULL, &subtable->Coverage));
916           IPRINT ("(ValueFormat #x%04X)",
917                   subtable->u.single1.ValueFormat);
918           dump_value_record (indent, "Value", &subtable->u.single1.Value);
919         }
920       else if (subtable->Format == 2)
921         {
922           int i;
923
924           free (dump_coverage (indent, NULL, &subtable->Coverage));
925           IPRINT ("(ValueFormat #x%04X)",
926                   subtable->u.single2.ValueFormat);
927           IPRINT ("(ValueCount %d)",
928                   subtable->u.single2.ValueCount);
929           for (i = 0; i < subtable->u.single2.ValueCount; i++)
930             dump_value_record (indent, "Value", &subtable->u.single2.Value[i]);
931         }
932       else
933         printf (" invalid");
934       break;
935
936     case 2:
937       if (subtable->Format == 1)
938         {
939           free (dump_coverage (indent, NULL, &subtable->Coverage));
940           IPRINT ("(ValueFormat1 #x%04X)",
941                   subtable->u.pair1.ValueFormat1);
942           IPRINT ("(ValueFormat2 #x%04X)",
943                   subtable->u.pair1.ValueFormat2);
944           dump_pair_set_list (indent, subtable->u.pair1.PairSetCount,
945                               subtable->u.pair1.PairSet);
946         }
947       else if (subtable->Format == 2)
948         {
949           free (dump_coverage (indent, NULL, &subtable->Coverage));
950           IPRINT ("(ValueFormat1 #x%04X)",
951                   subtable->u.pair2.ValueFormat1);
952           IPRINT ("(ValueFormat2 #x%04X)",
953                   subtable->u.pair2.ValueFormat2);
954           dump_class_def (indent, "ClassDef1",
955                           &subtable->u.pair2.ClassDef1);
956           dump_class_def (indent, "ClassDef2",
957                           &subtable->u.pair2.ClassDef2);
958           IPRINT ("(Class1Count %d)",
959                   subtable->u.pair2.Class1Count);
960           IPRINT ("(Class2Count %d)",
961                   subtable->u.pair2.Class2Count);
962           dump_class1_record_list (indent,
963                                    subtable->u.pair2.Class1Count,
964                                    subtable->u.pair2.Class2Count,
965                                    subtable->u.pair2.Class1Record);
966         }
967       else
968         printf (" invalid");
969       break;
970       
971     case 3:
972       if (subtable->Format == 1)
973         {
974           free (dump_coverage (indent, NULL, &subtable->Coverage));
975           dump_entry_exit_list (indent, subtable->u.cursive1.EntryExitCount,
976                                 subtable->u.cursive1.EntryExitRecord);
977         }
978       else
979         printf (" invalid");
980       break;
981
982     case 4:
983       if (subtable->Format == 1)
984         {
985           free (dump_coverage (indent, "Mark", &subtable->Coverage));
986           free (dump_coverage (indent, "Base",
987                                &subtable->u.mark_base1.BaseCoverage));
988           IPRINT ("(ClassCount %d)",
989                   subtable->u.mark_base1.ClassCount);
990           dump_mark_array (indent, &subtable->u.mark_base1.MarkArray);
991           dump_anchor_array (indent, subtable->u.mark_base1.ClassCount,
992                            &subtable->u.mark_base1.BaseArray);
993         }
994       break;
995
996     case 5:
997       if (subtable->Format == 1)
998         {
999           printf (" not-yet-supported");
1000         }
1001       else
1002         printf (" invalid");
1003       break;
1004
1005     case 6:
1006       if (subtable->Format == 1)
1007         {
1008           free (dump_coverage (indent, "Mark1", &subtable->Coverage));
1009           free (dump_coverage (indent, "Mark2",
1010                                &subtable->u.mark_mark1.Mark2Coverage));
1011           IPRINT ("(ClassCount %d)",
1012                   subtable->u.mark_mark1.ClassCount);
1013           dump_mark_array (indent, &subtable->u.mark_mark1.Mark1Array);
1014           dump_anchor_array (indent, subtable->u.mark_mark1.ClassCount,
1015                            &subtable->u.mark_mark1.Mark2Array);
1016         }
1017       else
1018         printf (" invalid");
1019       break;
1020
1021     case 7:
1022       if (subtable->Format == 1)
1023         {
1024           free (dump_coverage (indent, NULL, &subtable->Coverage));
1025           dump_rule_set_list (indent, subtable->u.context1.RuleSet,
1026                               subtable->u.context1.RuleSetCount); 
1027         }
1028       else if (subtable->Format == 2)
1029         {
1030           free (dump_coverage (indent, NULL, &subtable->Coverage));
1031           dump_class_def (indent, NULL, &subtable->u.context2.ClassDef);
1032           dump_class_set_list (indent, subtable->u.context2.ClassSet,
1033                                subtable->u.context2.ClassSetCnt);
1034         }
1035       else if (subtable->Format == 3)
1036         {
1037           dump_coverage_list (indent, "Coverage",
1038                               subtable->u.context3.Coverage,
1039                               subtable->u.context3.GlyphCount);
1040           dump_lookup_record_list (indent,
1041                                    subtable->u.context3.LookupRecord,
1042                                    subtable->u.context3.LookupCount);
1043         }
1044       else
1045         printf (" invalid");
1046       break;
1047
1048     case 8:
1049       if (subtable->Format == 1)
1050         {
1051           free (dump_coverage (indent, NULL, &subtable->Coverage));
1052           dump_chain_rule_set_list
1053             (indent,
1054              subtable->u.chain_context1.ChainRuleSet,
1055              subtable->u.chain_context1.ChainRuleSetCount);
1056         }
1057       else if (subtable->Format == 2)
1058         {
1059           free (dump_coverage (indent, NULL, &subtable->Coverage));
1060           dump_class_def (indent, "BacktrackClassDef",
1061                           &subtable->u.chain_context2.BacktrackClassDef);
1062           dump_class_def (indent, "InputClassDef",
1063                           &subtable->u.chain_context2.InputClassDef);
1064           dump_class_def (indent, "LookaheadClassDef",
1065                           &subtable->u.chain_context2.LookaheadClassDef);
1066           dump_chain_class_set_list
1067             (indent,
1068              subtable->u.chain_context2.ChainClassSet,
1069              subtable->u.chain_context2.ChainClassSetCnt);
1070         }
1071       else if (subtable->Format == 3)
1072         {
1073           dump_coverage_list
1074             (indent, "BackTrackGlyphCount",
1075              subtable->u.chain_context3.Backtrack,
1076              subtable->u.chain_context3.BacktrackGlyphCount);
1077           dump_coverage_list
1078             (indent, "InputGlyphCount",
1079              subtable->u.chain_context3.Input,
1080              subtable->u.chain_context3.InputGlyphCount);
1081           dump_coverage_list
1082             (indent, "LookaheaGlyphCount",
1083              subtable->u.chain_context3.LookAhead,
1084              subtable->u.chain_context3.LookaheadGlyphCount);
1085           dump_lookup_record_list
1086             (indent,
1087              subtable->u.chain_context3.LookupRecord,
1088              subtable->u.chain_context3.LookupCount);
1089         }
1090       else
1091         printf (" invalid");
1092       break;
1093     }
1094   printf (")");
1095 }
1096
1097
1098 static void
1099 dump_gpos_table (int indent, OTF_GPOS *gpos)
1100 {
1101   if (! gpos)
1102     return;
1103   IPRINT ("(GPOS");
1104   indent++;
1105   IPRINT ("(Header");
1106   indent++;
1107   IPRINT ("(Version %d.%d)", gpos->Version.high, gpos->Version.low);
1108   IPRINT ("(ScriptList #x%04X)", gpos->ScriptList.offset);
1109   IPRINT ("(FeatureList #x%04X)", gpos->FeatureList.offset);
1110   IPRINT ("(LookupList #x%04X))", gpos->LookupList.offset);
1111   indent--;
1112   dump_script_list (indent, &gpos->ScriptList);
1113   dump_feature_list (indent, &gpos->FeatureList);
1114   dump_lookup_list (indent, &gpos->LookupList, 0);
1115   printf (")");
1116 }
1117
1118 #if 0
1119 static void
1120 dump_base_table (OTF_BASE *base)
1121 {
1122 }
1123
1124 static void
1125 dump_jstf_table (OTF_JSTF *jstf)
1126 {
1127 }
1128 #endif
1129
1130 \f
1131 /* GDEF */
1132 static void
1133 dump_gdef_header (int indent, OTF_GDEFHeader *header)
1134 {
1135   IPRINT ("(Header");
1136   indent++;
1137   IPRINT ("(Version %d.%d)",
1138           header->Version.high, header->Version.low);
1139   IPRINT ("(GlyphClassDef #x%04X)", header->GlyphClassDef);
1140   IPRINT ("(AttachList #x%04X)", header->AttachList);
1141   IPRINT ("(LigCaretList #x%04X)", header->LigCaretList);
1142   IPRINT ("(MarkAttachClassDef #x%04X))",
1143           header->MarkAttachClassDef);
1144 }
1145
1146 static void
1147 dump_attach_list (int indent, OTF_AttachList *list)
1148 {
1149 }
1150
1151 static void
1152 dump_lig_caret_list (int indent, OTF_LigCaretList *list)
1153 {
1154   int i, j;
1155
1156   IPRINT ("(LigCaretList");
1157   indent++;
1158   free (dump_coverage (indent, NULL, &list->Coverage));
1159   IPRINT ("(LigGlyphCount %d)", list->LigGlyphCount);
1160   for (i = 0; i < list->LigGlyphCount; i++)
1161     {
1162       IPRINT ("(LigGlyph (%d) (offset #x%04X)",
1163               i, list->LigGlyph[i].offset);
1164       indent++;
1165       IPRINT ("(CaretCount %d)", list->LigGlyph[i].CaretCount);
1166       for (j = 0; j < list->LigGlyph[i].CaretCount; j++)
1167         {
1168           unsigned format = list->LigGlyph[i].CaretValue[j].CaretValueFormat;
1169
1170           IPRINT ("(Caret (%d) (CaretValueFormat %d)", j, format);
1171           if (format == 1)
1172             {
1173               printf ("(Coordinate %d)",
1174                       list->LigGlyph[i].CaretValue[j].f.f1.Coordinate);
1175             }
1176           else if (format == 2)
1177             {
1178               printf ("(CaretValuePoint %d)",
1179                       list->LigGlyph[i].CaretValue[j].f.f2.CaretValuePoint);
1180             }
1181           else if (format == 3)
1182             {
1183               printf ("(Coodinate %d)",
1184                       list->LigGlyph[i].CaretValue[j].f.f3.Coordinate);
1185               indent++;
1186               dump_device_table
1187                 (indent, "DeviceTable", 
1188                  &list->LigGlyph[i].CaretValue[j].f.f3.DeviceTable);
1189               indent--;
1190             }
1191           printf (")");
1192         }
1193       printf (")");
1194     }
1195   printf (")");
1196 }
1197
1198
1199 static void
1200 dump_gdef_table (int indent, OTF_GDEF *gdef)
1201 {
1202   if (! gdef)
1203     return;
1204   IPRINT ("(GDEF");
1205   indent++;
1206   dump_gdef_header (indent, &gdef->header);
1207   if (gdef->header.GlyphClassDef)
1208     dump_class_def (indent, "GlyphClassDef", &gdef->glyph_class_def);
1209   if (gdef->header.AttachList)
1210     dump_attach_list (indent, &gdef->attach_list);
1211   if (gdef->header.LigCaretList)
1212     dump_lig_caret_list (indent, &gdef->lig_caret_list);
1213   if (gdef->header.MarkAttachClassDef)
1214     dump_class_def (indent, "MarkAttachClassDef",
1215                     &gdef->mark_attach_class_def);
1216   printf (")");
1217 }
1218
1219 \f
1220 /* cmap */
1221 static void
1222 dump_cmap_table (int indent, OTF_cmap *cmap)
1223 {
1224   int i;
1225
1226   IPRINT ("(cmap");
1227   indent++;
1228   IPRINT ("(version %d)", cmap->version);
1229   IPRINT ("(numTables %d)", cmap->numTables);
1230   for (i = 0; i < cmap->numTables; i++)
1231     {
1232       IPRINT ("(EncodingRecord (%d) (platformID %d) (encodingID %d)",
1233               i,
1234               cmap->EncodingRecord[i].platformID,
1235               cmap->EncodingRecord[i].encodingID);
1236       indent++;
1237       IPRINT ("(Subtable (offset #x%04X) (format %d) (length #x%04X) (language %d)",
1238               cmap->EncodingRecord[i].offset,
1239               cmap->EncodingRecord[i].subtable.format,
1240               cmap->EncodingRecord[i].subtable.length,
1241               cmap->EncodingRecord[i].subtable.language);
1242       indent++;
1243       switch (cmap->EncodingRecord[i].subtable.format)
1244         {
1245         case 0:
1246           {
1247             int j, k;
1248             unsigned char *array
1249               = cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray;
1250
1251             IPRINT ("(glyphIdArray");
1252             for (j = 0; j < 16; j++)
1253               {
1254                 IPRINT (" ");
1255                 for (k = 0; k < 16; k++)
1256                   printf (" %3d", array[j * 16 + k]);
1257               }
1258             printf (")");
1259           }
1260           break;
1261
1262         case 4:
1263           {
1264             OTF_EncodingSubtable4 *sub4
1265               = cmap->EncodingRecord[i].subtable.f.f4;
1266             int j;
1267
1268             IPRINT ("(segCountX2 %d) (searchRange %d)",
1269                     sub4->segCountX2, sub4->searchRange);
1270             IPRINT ("(entrySelector %d) (rangeShift %d)",
1271                     sub4->entrySelector, sub4->rangeShift);
1272             for (j = 0; j < sub4->segCountX2 / 2; j++)
1273               {
1274                 IPRINT ("(Segment (%d)", j);
1275                 indent++;
1276                 IPRINT ("(startCount #x%04X) (endCount #x%04X)",
1277                         sub4->segments[j].startCount,
1278                         sub4->segments[j].endCount);
1279                 IPRINT ("(idDelta %d) (idRangeOffset #x%04X))",
1280                         sub4->segments[j].idDelta,
1281                         sub4->segments[j].idRangeOffset);
1282                 indent--;
1283               }
1284             IPRINT ("(glyphIdArray");
1285             for (j = 0; j < sub4->GlyphCount; j++)
1286               {
1287                 if ((j % 16) == 0)
1288                   IPRINT (" ");
1289                 printf (" %3d", sub4->glyphIdArray[j]);
1290               }
1291             printf (")");
1292           }
1293           break;
1294
1295         case 6:
1296           {
1297             OTF_EncodingSubtable6 *sub6
1298               = cmap->EncodingRecord[i].subtable.f.f6;
1299             int j;
1300
1301             IPRINT ("(firstCode %d) (entryCount %d)",
1302                     sub6->firstCode, sub6->entryCount);
1303             IPRINT ("(glyphIdArray");
1304             for (j = 0; j < sub6->entryCount; j++)
1305               {
1306                 if ((j % 16) == 0)
1307                   IPRINT (" ");
1308                 printf (" %3d", sub6->glyphIdArray[j]);
1309               }
1310             printf (")");
1311           }
1312           break;
1313         }
1314
1315       indent -= 2;
1316       printf ("))");
1317     }
1318   printf (")");
1319 }
1320 \f
1321
1322 /* name */
1323 static void
1324 dump_name_table (int indent, OTF_name *name)
1325 {
1326   int i;
1327
1328   IPRINT ("(name");
1329   indent++;
1330   IPRINT ("(format %d)", name->format);
1331   IPRINT ("(count %d)", name->count);
1332   IPRINT ("(stringOffset %d)", name->stringOffset);
1333   for (i = 0; i < name->count; i++)
1334     {
1335       OTF_NameRecord *rec = name->nameRecord + i; 
1336
1337       IPRINT ("(nameRecord (%d)", i);
1338       indent++;
1339       IPRINT ("(platformID %d) (encodingID %d) (languageID %d) (nameID %d)",
1340               rec->platformID, rec->encodingID, rec->languageID, rec->nameID);
1341       IPRINT ("(length %d) (offset #x%04X))", rec->length, rec->offset);
1342       indent--;
1343     }
1344   for (i = 0; i <= OTF_max_nameID; i++)
1345     if (name->name[i])
1346       IPRINT ("(nameID %d \"%s\")", i, name->name[i]);
1347
1348   printf (")");
1349 }
1350
1351 \f
1352
1353 static void
1354 otf_dump (OTF *otf)
1355 {
1356   int i;
1357
1358   printf ("(OTF");
1359
1360   dump_offset_table (1, &otf->offset_table);
1361   for (i = 0; i < otf->offset_table.numTables; i++)
1362     dump_table_directory (1, otf->table_dirs + i, i);
1363
1364   if (otf->head)
1365     dump_head_table (1, otf->head);
1366   if (otf->name)
1367     dump_name_table (1, otf->name);
1368   if (otf->cmap)
1369     dump_cmap_table (1, otf->cmap);
1370   if (otf->gdef)
1371     dump_gdef_table (1, otf->gdef);
1372   if (otf->gsub)
1373     dump_gsub_table (1, otf->gsub);
1374   if (otf->gpos)
1375     dump_gpos_table (1, otf->gpos);
1376 #if 0
1377   if (otf->base)
1378     dump_base_table (1, otf->base);
1379   if (otf->jstf)
1380     dump_jstf_table (1, otf->jstf);
1381 #endif
1382   printf (")\n");
1383 }
1384
1385
1386 int
1387 main (int argc, char **argv)
1388 {
1389   OTF *otf;
1390
1391   if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1392     {
1393       fprintf (stderr, "Usage: %s OTF-FILE\n", basename (argv[0]));
1394       exit (argc != 2);
1395     }
1396   
1397   otf = OTF_open (argv[1]);
1398   if (! otf)
1399     {
1400       OTF_perror ("otfdump");
1401       exit (1);
1402     }
1403   OTF_get_table (otf, "head");
1404   OTF_get_table (otf, "name");
1405   OTF_get_table (otf, "cmap");
1406   OTF_get_table (otf, "GDEF");
1407   OTF_get_table (otf, "GSUB");
1408   OTF_get_table (otf, "GPOS");
1409 #if 0
1410   OTF_get_table (otf, "BASE");
1411   OTF_get_table (otf, "JSTF");
1412 #endif
1413   otf_dump (otf);
1414   OTF_close (otf);
1415   exit (0);
1416 }