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