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