2f9dda3d863635b2c9df004dc162418aa05ac26f
[m17n/libotf.git] / example / otfdump.c
1 /* otfdump.c -- Dump OpenType Layout Tables.
2
3 Copyright (C) 2003, 2004, 2008, 2009, 2010
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   if (table->DeltaValue)
310     {
311       IPRINT ("(DeltaValue");
312       for (i = 0; i < table->EndSize - table->StartSize + 1; i++)
313         printf (" %d", table->DeltaValue[i]);
314       printf (")");
315     }
316   printf (")");
317 }
318
319 \f
320
321 static void
322 dump_value_record (int indent, char *title, OTF_ValueRecord *rec)
323 {
324   IPRINT ("(%s %d %d %d %d", title,
325           rec->XPlacement, rec->YPlacement, rec->XAdvance, rec->YAdvance);
326   indent++;
327   if (rec->XPlaDevice.offset)
328     dump_device_table (indent, "XPlaDevice", &rec->XPlaDevice);
329   if (rec->YPlaDevice.offset)
330     dump_device_table (indent, "YPlaDevice", &rec->YPlaDevice);
331   if (rec->XAdvDevice.offset)
332     dump_device_table (indent, "XAdvDevice", &rec->XAdvDevice);
333   if (rec->YAdvDevice.offset)
334     dump_device_table (indent, "YAdvDevice", &rec->YAdvDevice);
335   printf (")");
336 }
337
338
339 static void
340 dump_sequence_list (int indent, OTF_Sequence *sequence, unsigned num)
341 {
342   int i;
343   IPRINT ("(SequenceCount %d)", num);
344
345   for (i = 0; i < num; i++)
346     {
347       IPRINT ("(Sequence (%d) (offset #x%04X)",
348               i, sequence[i].offset);
349       dump_glyph_ids (indent + 1, "Substitute", sequence[i].Substitute,
350                       sequence[i].GlyphCount);
351       printf (")");
352     }
353 }
354
355 static void
356 dump_alternate_set_list (int indent, OTF_AlternateSet *altset, unsigned num)
357 {
358   int i;
359
360   IPRINT ("(AlternateSetCount %d)", num);
361   for (i = 0; i < num; i++)
362     {
363       IPRINT ("(AlternateSet (%d) (offset #x%04X)",
364               i, altset[i].offset);
365       dump_glyph_ids (indent + 1, "Alternate", altset[i].Alternate,
366                       altset[i].GlyphCount);
367       printf (")");
368     }
369 }
370
371
372 static void
373 dump_ligature_set_list (int indent, int *char_list,
374                         OTF_LigatureSet *ligset, unsigned num)
375 {
376   int i, j, k;
377
378   IPRINT ("(LigSetCount %d)", num);
379   for (i = 0; i < num; i++)
380     {
381       IPRINT ("(LigatureSet (%d) (offset #x%04X) (count %d)",
382               i, ligset[i].offset, ligset[i].LigatureCount);
383       indent++;
384       for (j = 0; j < ligset[i].LigatureCount; j++)
385         {
386           IPRINT ("(Ligature (%d) (offset #x%04X)",
387                   j, ligset[i].Ligature[j].offset);
388           indent++;
389           IPRINT ("(LigGlyph #x%04X)",
390                   ligset[i].Ligature[j].LigGlyph);
391           dump_glyph_ids (indent, "Component", ligset[i].Ligature[j].Component,
392                           ligset[i].Ligature[j].CompCount - 1);
393           IPRINT ("(i.e. #x%04X", char_list[i]);
394           for (k = 0; k < ligset[i].Ligature[j].CompCount - 1; k++)
395             printf (" #x%04X", ligset[i].Ligature[j].Component[k]);
396           printf (" = #x%04X)", ligset[i].Ligature[j].LigGlyph);
397           printf (")");
398           indent--;
399         }
400       indent--;
401       printf (")");
402     }
403 }
404
405 static void
406 dump_pair_set_list (int indent, unsigned count, OTF_PairSet *set)
407 {
408   int i, j;
409
410   for (i = 0; i < count; i++)
411     {
412       IPRINT ("(PairSet (%d)", i);
413       indent++;
414       for (j = 0; j < set[i].PairValueCount; j++)
415         {
416           IPRINT ("(PairValueRecord (%d)", j);
417           indent++;
418           IPRINT ("(SecondGlyph #x%04X)",
419                   set[i].PairValueRecord[j].SecondGlyph);
420           dump_value_record (indent, "Value1",
421                              &set[i].PairValueRecord[j].Value1);
422           dump_value_record (indent, "Value2",
423                              &set[i].PairValueRecord[j].Value2);
424           printf (")");
425           indent--;
426         }
427       printf (")");
428       indent--;
429     }
430 }
431
432 static void
433 dump_class1_record_list (int indent,
434                          unsigned Class1Count, unsigned Class2Count,
435                          OTF_Class1Record *rec)
436 {
437   int i, j;
438
439   for (i = 0; i < Class1Count; i++)
440     {
441       IPRINT ("(Class1Record (%d)", i);
442       indent++;
443       for (j = 0; j < Class2Count; j++)
444         {
445           IPRINT ("(Class2Record (%d)", j);
446           indent++;
447           dump_value_record (indent, "Value1", &rec[i].Class2Record[j].Value1);
448           dump_value_record (indent, "Value2", &rec[i].Class2Record[j].Value2);
449           printf (")");
450           indent--;
451         }
452       printf (")");
453       indent--;
454     }
455 }
456
457 static void
458 dump_anchor (int indent, OTF_Anchor *anchor)
459 {
460   IPRINT ("(Anchor (offset #x%04X) (AnchorFormat %d)",
461           anchor->offset, anchor->AnchorFormat);
462   indent++;
463   IPRINT ("(XCoordinate %d) (YCoordinate %d)",
464           anchor->XCoordinate, anchor->YCoordinate);
465   if (anchor->AnchorFormat == 1)
466     ;
467   else if (anchor->AnchorFormat == 2)
468     IPRINT ("(AnchorPoint %d)", anchor->f.f1.AnchorPoint);
469   else
470     {
471       dump_device_table (indent, "XDeviceTable", &anchor->f.f2.XDeviceTable);
472       dump_device_table (indent, "YDeviceTable", &anchor->f.f2.YDeviceTable);
473     }
474   printf (")");
475 }
476
477 static void
478 dump_entry_exit_list (int indent, unsigned count, OTF_EntryExitRecord *rec)
479 {
480   int i;
481
482   for (i = 0; i < count; i++)
483     {
484       IPRINT ("(EntryExitRecord (%d)", i);
485       indent++;
486       dump_anchor (indent, &rec[i].EntryAnchor);
487       dump_anchor (indent, &rec[i].EntryAnchor);
488       printf (")");
489       indent--;
490     }
491 }
492
493 static void
494 dump_mark_array (int indent, OTF_MarkArray *array)
495 {
496   int i;
497
498   IPRINT ("(MarkArray (MarkCount %d)", array->MarkCount);
499   indent++;
500   for (i = 0; i < array->MarkCount; i++)
501     {
502       IPRINT ("(MarkRecord (%d) (Class %d)", i, array->MarkRecord[i].Class);
503       dump_anchor (indent + 1, &array->MarkRecord[i].MarkAnchor);
504       printf (")");
505     }
506   printf (")");
507 }
508
509 static void
510 dump_anchor_array (int indent, unsigned ClassCount, OTF_AnchorArray *array)
511 {
512   int i, j;
513
514   IPRINT ("(AnchorArray (Count %d)", array->Count);
515   indent++;
516   for (i = 0; i < array->Count; i++)
517     {
518       IPRINT ("(AnchorRecord (%d) ", i);
519       for (j = 0; j < ClassCount; j++)
520         dump_anchor (indent + 1, array->AnchorRecord[i].Anchor + j);
521       printf (")");
522     }
523   printf (")");
524 }
525
526
527 static void
528 dump_lookup_record_list (int indent, OTF_LookupRecord *rec, unsigned num)
529 {
530   int i;
531
532   IPRINT ("(LookupCount %d)", num);
533   for (i = 0; i < num; i++)
534     {
535       IPRINT ("(LookupRecord (%d)", i);
536       indent++;
537       IPRINT ("(SequenceIndex %d)", rec[i].SequenceIndex);
538       IPRINT ("(LookupListIndex %d))", rec[i].LookupListIndex);
539       indent--;
540     }
541 }
542
543
544 static void dump_lookup_subtable_gsub (int indent, int index, unsigned type,
545                                        OTF_LookupSubTableGSUB *subtable);
546 static void dump_lookup_subtable_gpos (int indent, int index, unsigned type,
547                                        OTF_LookupSubTableGPOS *subtable);
548
549
550 static void
551 dump_lookup_list (int indent, OTF_LookupList *list, int gsub)
552 {
553   int i, j;
554
555   IPRINT ("(LookupList (count %d)", list->LookupCount);
556   indent++;
557   for (i = 0; i < list->LookupCount; i++)
558     {
559       OTF_Lookup *lookup = list->Lookup + i;
560
561       IPRINT ("(Lookup (%d) (Offset #x%04X)",
562               i, lookup->offset);
563       printf (" (Type %d) (Flag #x%04X) (SubTableCount %d)",
564               lookup->LookupType, lookup->LookupFlag, lookup->SubTableCount);
565       if (gsub)
566         for (j = 0; j < lookup->SubTableCount; j++)
567           dump_lookup_subtable_gsub (indent + 1, j,
568                                      lookup->LookupType,
569                                      lookup->SubTable.gsub + j);
570       else
571         for (j = 0; j < lookup->SubTableCount; j++)
572           dump_lookup_subtable_gpos (indent + 1, j,
573                                      lookup->LookupType,
574                                      lookup->SubTable.gpos + j);
575
576       printf (")");
577     }
578   printf (")");
579 }
580
581 static void
582 dump_rule_list (int indent, OTF_Rule *rule, int count)
583 {
584   int i;
585
586   IPRINT ("(RuleCount %d)", count);
587   for (i = 0; i < count; i++)
588     {
589       IPRINT ("(Rule (%d)", i);
590       indent++;
591       IPRINT ("(GlyphCount %d)", rule[i].GlyphCount);
592       IPRINT ("(LookupCount %d)", rule[i].LookupCount);
593       dump_glyph_ids (indent, "Input", rule[i].Input, rule[i].GlyphCount - 1);
594       dump_lookup_record_list (indent, rule[i].LookupRecord,
595                                rule[i].LookupCount);
596       printf (")");
597       indent--;
598     }
599 }
600
601 static void
602 dump_rule_set_list (int indent, OTF_RuleSet *set, int count)
603 {
604   int i;
605
606   IPRINT ("(RuleSetCount %d)", count);
607   for (i = 0; i < count; i++)
608     {
609       IPRINT ("(RuleSet (%d)", i);
610       dump_rule_list (indent + 1, set[i].Rule, set[i].RuleCount);
611       printf (")");
612     }
613 }
614
615 static void
616 dump_class_rule_list (int indent, OTF_ClassRule *rule, int count)
617 {
618   int i, j;
619
620   IPRINT ("(ClassRuleCnt %d)", count);
621   for (i = 0; i < count; i++)
622     {
623       IPRINT ("(ClassRule (%d)", i);
624       indent++;
625       IPRINT ("(GlyphCount %d)", rule[i].GlyphCount);
626       IPRINT ("(LookupCount %d)", rule[i].LookupCount);
627       IPRINT ("(Class");
628       for (j = 0; j < rule[i].GlyphCount - 1; j++)
629         printf (" %d", rule[i].Class[j]);
630       printf (")");
631       dump_lookup_record_list (indent, rule[i].LookupRecord,
632                                rule[i].LookupCount);
633       printf (")");
634       indent--;
635     }
636 }
637
638 static void
639 dump_class_set_list (int indent, OTF_ClassSet *set, int count)
640 {
641   int i;
642
643   IPRINT ("(ClassSetCount %d)", count);
644   for (i = 0; i < count; i++)
645     if (set[i].offset)
646       {
647         IPRINT ("(ClassSet (%d)", i);
648         dump_class_rule_list (indent + 1, set[i].ClassRule,
649                               set[i].ClassRuleCnt);
650         printf (")");
651       }
652 }
653
654 static void
655 dump_chain_rule_list (int indent, OTF_ChainRule *rule, int count)
656 {
657   int i;
658
659   IPRINT ("(ChainRuleCount %d)", count);
660   for (i = 0; i < count; i++)
661     {
662       IPRINT ("(ChainRule (%d)", i);
663       dump_glyph_ids (indent + 1, "Backtrack",
664                       rule[i].Backtrack, rule[i].BacktrackGlyphCount);
665       dump_glyph_ids (indent + 1, "Input",
666                       rule[i].Input, rule[i].InputGlyphCount - 1);
667       dump_glyph_ids (indent + 1, "LookAhead",
668                       rule[i].LookAhead, rule[i].LookaheadGlyphCount);
669       dump_lookup_record_list (indent + 1, rule[i].LookupRecord,
670                                rule[i].LookupCount);
671       printf (")");
672     }
673 }
674
675 static void
676 dump_chain_rule_set_list (int indent, OTF_ChainRuleSet *set, int count)
677 {
678   int i;
679
680   IPRINT ("(ChainRuleSetCount %d)", count);
681   for (i = 0; i < count; i++)
682     {
683       IPRINT ("(ChainRuleSet (%d)", i);
684       dump_chain_rule_list (indent + 1,
685                             set[i].ChainRule, set[i].ChainRuleCount);
686       printf (")");
687     }
688 }
689
690 static void
691 dump_chain_class_rule_list (int indent, OTF_ChainClassRule *rule, int count)
692 {
693   int i;
694
695   IPRINT ("(ChainClassRuleCount %d)", count);
696   for (i = 0; i < count; i++)
697     {
698       IPRINT ("(ChainClassRule (%d)", i);
699       dump_glyph_ids (indent + 1, "Backtrack",
700                       rule[i].Backtrack, rule[i].BacktrackGlyphCount);
701       dump_glyph_ids (indent + 1, "Input",
702                       rule[i].Input, rule[i].InputGlyphCount - 1);
703       dump_glyph_ids (indent + 1, "LookAhead",
704                       rule[i].LookAhead, rule[i].LookaheadGlyphCount);
705       dump_lookup_record_list (indent + 1, rule[i].LookupRecord,
706                                rule[i].LookupCount);
707       printf (")");
708     }
709 }
710
711 static void
712 dump_chain_class_set_list (int indent, OTF_ChainClassSet *set, int count)
713 {
714   int i;
715
716   IPRINT ("(ChainClassSetCount %d)", count);
717   for (i = 0; i < count; i++)
718     if (set[i].offset)
719       {
720         IPRINT ("(ChainClassSet (%d)", i);
721         dump_chain_class_rule_list (indent + 1,
722                                     set[i].ChainClassRule,
723                                     set[i].ChainClassRuleCnt);
724         printf (")");
725       }
726 }
727
728
729
730
731 \f
732 /* GSUB */
733
734 static void
735 dump_lookup_subtable_gsub (int indent, int index, unsigned type,
736                            OTF_LookupSubTableGSUB *subtable)
737 {
738   IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format);
739   indent++;
740   switch (type)
741     {
742     case 1:
743       if (subtable->Format == 1)
744         {
745           free (dump_coverage (indent, NULL, &subtable->Coverage));
746           IPRINT ("(DeltaGlyhpID #x%04X)",
747                   subtable->u.single1.DeltaGlyphID);
748         }
749       else if (subtable->Format == 2)
750         {
751           free (dump_coverage (indent, NULL, &subtable->Coverage));
752           dump_glyph_ids (indent, "Substitute", subtable->u.single2.Substitute,
753                           subtable->u.single2.GlyphCount);
754         }
755       else
756         printf (" invalid");
757       break;
758
759     case 2:
760       if (subtable->Format == 1)
761         {
762           free (dump_coverage (indent, NULL, &subtable->Coverage));
763           dump_sequence_list (indent,
764                               subtable->u.multiple1.Sequence,
765                               subtable->u.multiple1.SequenceCount);
766         }
767       else
768         printf (" invalid");
769       break;
770       
771     case 3:
772       if (subtable->Format == 1)
773         {
774           free (dump_coverage (indent, NULL, &subtable->Coverage));
775           dump_alternate_set_list (indent, subtable->u.alternate1.AlternateSet,
776                                    subtable->u.alternate1.AlternateSetCount);
777         }
778       else
779         printf (" invalid");
780       break;
781
782     case 4:
783       if (subtable->Format == 1)
784         {
785           int *char_list = dump_coverage (indent, NULL, &subtable->Coverage);
786           dump_ligature_set_list (indent, char_list,
787                                   subtable->u.ligature1.LigatureSet,
788                                   subtable->u.ligature1.LigSetCount);
789           free (char_list);
790         }
791       else
792         printf (" invalid");
793       break;
794
795     case 5:
796       if (subtable->Format == 1)
797         {
798           free (dump_coverage (indent, NULL, &subtable->Coverage));
799           dump_rule_set_list (indent, subtable->u.context1.RuleSet,
800                               subtable->u.context1.RuleSetCount); 
801         }
802       else if (subtable->Format == 2)
803         {
804           free (dump_coverage (indent, NULL, &subtable->Coverage));
805           dump_class_def (indent, NULL, &subtable->u.context2.ClassDef);
806           dump_class_set_list (indent, subtable->u.context2.ClassSet,
807                                subtable->u.context2.ClassSetCnt);
808         }
809       else if (subtable->Format == 3)
810         {
811           dump_coverage_list (indent, "Coverage",
812                               subtable->u.context3.Coverage,
813                               subtable->u.context3.GlyphCount);
814           dump_lookup_record_list (indent,
815                                    subtable->u.context3.LookupRecord,
816                                    subtable->u.context3.LookupCount);
817         }
818       else
819         printf (" invalid");
820       break;
821
822     case 6:
823       if (subtable->Format == 1)
824         {
825           free (dump_coverage (indent, NULL, &subtable->Coverage));
826           dump_chain_rule_set_list
827             (indent,
828              subtable->u.chain_context1.ChainRuleSet,
829              subtable->u.chain_context1.ChainRuleSetCount);
830         }
831       else if (subtable->Format == 2)
832         {
833           free (dump_coverage (indent, NULL, &subtable->Coverage));
834           dump_class_def (indent, "BacktrackClassDef",
835                           &subtable->u.chain_context2.BacktrackClassDef);
836           dump_class_def (indent, "InputClassDef",
837                           &subtable->u.chain_context2.InputClassDef);
838           dump_class_def (indent, "LookaheadClassDef",
839                           &subtable->u.chain_context2.LookaheadClassDef);
840           dump_chain_class_set_list
841             (indent,
842              subtable->u.chain_context2.ChainClassSet,
843              subtable->u.chain_context2.ChainClassSetCnt);
844         }
845       else if (subtable->Format == 3)
846         {
847           dump_coverage_list
848             (indent, "BackTrackGlyphCount",
849              subtable->u.chain_context3.Backtrack,
850              subtable->u.chain_context3.BacktrackGlyphCount);
851           dump_coverage_list
852             (indent, "InputGlyphCount",
853              subtable->u.chain_context3.Input,
854              subtable->u.chain_context3.InputGlyphCount);
855           dump_coverage_list
856             (indent, "LookaheadGlyphCount",
857              subtable->u.chain_context3.LookAhead,
858              subtable->u.chain_context3.LookaheadGlyphCount);
859           dump_lookup_record_list
860             (indent,
861              subtable->u.chain_context3.LookupRecord,
862              subtable->u.chain_context3.LookupCount);
863         }
864       else
865         printf (" invalid");
866       break;
867
868     case 7:
869       IPRINT ("(ExtensionLookupType %d)",
870               subtable->u.extension1.ExtensionLookupType);
871       IPRINT ("(ExtensionOffset %d)",
872               subtable->u.extension1.ExtensionOffset);
873       dump_lookup_subtable_gsub (indent, index, 
874                                  subtable->u.extension1.ExtensionLookupType,
875                                  subtable->u.extension1.ExtensionSubtable);
876       break;
877
878     case 8:
879       printf (" not-yet-supported");
880       break;
881
882     default:
883       printf (" invalid");
884     }
885   printf (")");
886 }
887
888 static void
889 dump_gsub_table (int indent, OTF_GSUB *gsub)
890 {
891   IPRINT ("(GSUB");
892   indent++;
893   IPRINT ("(Header");
894   indent++;
895   IPRINT ("(Version %d.%d)", gsub->Version.high, gsub->Version.low);
896   IPRINT ("(ScriptList #x%04X)", gsub->ScriptList.offset);
897   IPRINT ("(FeatureList #x%04X)", gsub->FeatureList.offset);
898   IPRINT ("(LookupList #x%04X))", gsub->LookupList.offset);
899   indent--;
900   dump_script_list (indent, &gsub->ScriptList);
901   dump_feature_list (indent, &gsub->FeatureList);
902   dump_lookup_list (indent, &gsub->LookupList, 1);
903   printf (")");
904 }
905
906 \f
907 /* GPOS */
908
909 static void
910 dump_lookup_subtable_gpos (int indent, int index, unsigned type,
911                            OTF_LookupSubTableGPOS *subtable)
912 {
913   IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format);
914   indent++;
915   switch (type)
916     {
917     case 1:
918       if (subtable->Format == 1)
919         {
920           free (dump_coverage (indent, NULL, &subtable->Coverage));
921           IPRINT ("(ValueFormat #x%04X)",
922                   subtable->u.single1.ValueFormat);
923           dump_value_record (indent, "Value", &subtable->u.single1.Value);
924         }
925       else if (subtable->Format == 2)
926         {
927           int i;
928
929           free (dump_coverage (indent, NULL, &subtable->Coverage));
930           IPRINT ("(ValueFormat #x%04X)",
931                   subtable->u.single2.ValueFormat);
932           IPRINT ("(ValueCount %d)",
933                   subtable->u.single2.ValueCount);
934           for (i = 0; i < subtable->u.single2.ValueCount; i++)
935             dump_value_record (indent, "Value", &subtable->u.single2.Value[i]);
936         }
937       else
938         printf (" invalid");
939       break;
940
941     case 2:
942       if (subtable->Format == 1)
943         {
944           free (dump_coverage (indent, NULL, &subtable->Coverage));
945           IPRINT ("(ValueFormat1 #x%04X)",
946                   subtable->u.pair1.ValueFormat1);
947           IPRINT ("(ValueFormat2 #x%04X)",
948                   subtable->u.pair1.ValueFormat2);
949           dump_pair_set_list (indent, subtable->u.pair1.PairSetCount,
950                               subtable->u.pair1.PairSet);
951         }
952       else if (subtable->Format == 2)
953         {
954           free (dump_coverage (indent, NULL, &subtable->Coverage));
955           IPRINT ("(ValueFormat1 #x%04X)",
956                   subtable->u.pair2.ValueFormat1);
957           IPRINT ("(ValueFormat2 #x%04X)",
958                   subtable->u.pair2.ValueFormat2);
959           dump_class_def (indent, "ClassDef1",
960                           &subtable->u.pair2.ClassDef1);
961           dump_class_def (indent, "ClassDef2",
962                           &subtable->u.pair2.ClassDef2);
963           IPRINT ("(Class1Count %d)",
964                   subtable->u.pair2.Class1Count);
965           IPRINT ("(Class2Count %d)",
966                   subtable->u.pair2.Class2Count);
967           dump_class1_record_list (indent,
968                                    subtable->u.pair2.Class1Count,
969                                    subtable->u.pair2.Class2Count,
970                                    subtable->u.pair2.Class1Record);
971         }
972       else
973         printf (" invalid");
974       break;
975       
976     case 3:
977       if (subtable->Format == 1)
978         {
979           free (dump_coverage (indent, NULL, &subtable->Coverage));
980           dump_entry_exit_list (indent, subtable->u.cursive1.EntryExitCount,
981                                 subtable->u.cursive1.EntryExitRecord);
982         }
983       else
984         printf (" invalid");
985       break;
986
987     case 4:
988       if (subtable->Format == 1)
989         {
990           free (dump_coverage (indent, "Mark", &subtable->Coverage));
991           free (dump_coverage (indent, "Base",
992                                &subtable->u.mark_base1.BaseCoverage));
993           IPRINT ("(ClassCount %d)",
994                   subtable->u.mark_base1.ClassCount);
995           dump_mark_array (indent, &subtable->u.mark_base1.MarkArray);
996           dump_anchor_array (indent, subtable->u.mark_base1.ClassCount,
997                            &subtable->u.mark_base1.BaseArray);
998         }
999       break;
1000
1001     case 5:
1002       if (subtable->Format == 1)
1003         {
1004           OTF_GPOS_MarkLig1 *mark_lig1 = &subtable->u.mark_lig1;
1005           int i, j, k;
1006
1007           free (dump_coverage (indent, "Mark", &subtable->Coverage));
1008           free (dump_coverage (indent, "Ligature",
1009                                &mark_lig1->LigatureCoverage));
1010           IPRINT ("(ClassCount %d)", mark_lig1->ClassCount);
1011           dump_mark_array (indent, &mark_lig1->MarkArray);
1012           IPRINT ("(LigatureArray (%d)",
1013                   mark_lig1->LigatureArray.LigatureCount);
1014           indent++;
1015           for (i = 0; i < mark_lig1->LigatureArray.LigatureCount; i++)
1016             {
1017               OTF_LigatureAttach *attach
1018                 = mark_lig1->LigatureArray.LigatureAttach + i;
1019
1020               IPRINT ("(LigatureAttach (%d)", attach->ComponentCount);
1021               indent++;
1022               for (j = 0; j < attach->ComponentCount; j++)
1023                 {
1024                   OTF_ComponentRecord *rec = attach->ComponentRecord + j;
1025
1026                   IPRINT ("(LigatureAnchor (%d)", mark_lig1->ClassCount);
1027                   for (k = 0; k < mark_lig1->ClassCount; k++)
1028                     if (rec->LigatureAnchor[k].AnchorFormat)
1029                       dump_anchor (indent + 1, rec->LigatureAnchor + k);
1030                   printf (")");
1031                 }
1032               printf (")");
1033               indent--;
1034             }
1035           printf (")");
1036         }
1037       else
1038         printf (" invalid");
1039       break;
1040
1041     case 6:
1042       if (subtable->Format == 1)
1043         {
1044           free (dump_coverage (indent, "Mark1", &subtable->Coverage));
1045           free (dump_coverage (indent, "Mark2",
1046                                &subtable->u.mark_mark1.Mark2Coverage));
1047           IPRINT ("(ClassCount %d)",
1048                   subtable->u.mark_mark1.ClassCount);
1049           dump_mark_array (indent, &subtable->u.mark_mark1.Mark1Array);
1050           dump_anchor_array (indent, subtable->u.mark_mark1.ClassCount,
1051                            &subtable->u.mark_mark1.Mark2Array);
1052         }
1053       else
1054         printf (" invalid");
1055       break;
1056
1057     case 7:
1058       if (subtable->Format == 1)
1059         {
1060           free (dump_coverage (indent, NULL, &subtable->Coverage));
1061           dump_rule_set_list (indent, subtable->u.context1.RuleSet,
1062                               subtable->u.context1.RuleSetCount); 
1063         }
1064       else if (subtable->Format == 2)
1065         {
1066           free (dump_coverage (indent, NULL, &subtable->Coverage));
1067           dump_class_def (indent, NULL, &subtable->u.context2.ClassDef);
1068           dump_class_set_list (indent, subtable->u.context2.ClassSet,
1069                                subtable->u.context2.ClassSetCnt);
1070         }
1071       else if (subtable->Format == 3)
1072         {
1073           dump_coverage_list (indent, "Coverage",
1074                               subtable->u.context3.Coverage,
1075                               subtable->u.context3.GlyphCount);
1076           dump_lookup_record_list (indent,
1077                                    subtable->u.context3.LookupRecord,
1078                                    subtable->u.context3.LookupCount);
1079         }
1080       else
1081         printf (" invalid");
1082       break;
1083
1084     case 8:
1085       if (subtable->Format == 1)
1086         {
1087           free (dump_coverage (indent, NULL, &subtable->Coverage));
1088           dump_chain_rule_set_list
1089             (indent,
1090              subtable->u.chain_context1.ChainRuleSet,
1091              subtable->u.chain_context1.ChainRuleSetCount);
1092         }
1093       else if (subtable->Format == 2)
1094         {
1095           free (dump_coverage (indent, NULL, &subtable->Coverage));
1096           dump_class_def (indent, "BacktrackClassDef",
1097                           &subtable->u.chain_context2.BacktrackClassDef);
1098           dump_class_def (indent, "InputClassDef",
1099                           &subtable->u.chain_context2.InputClassDef);
1100           dump_class_def (indent, "LookaheadClassDef",
1101                           &subtable->u.chain_context2.LookaheadClassDef);
1102           dump_chain_class_set_list
1103             (indent,
1104              subtable->u.chain_context2.ChainClassSet,
1105              subtable->u.chain_context2.ChainClassSetCnt);
1106         }
1107       else if (subtable->Format == 3)
1108         {
1109           dump_coverage_list
1110             (indent, "BackTrackGlyphCount",
1111              subtable->u.chain_context3.Backtrack,
1112              subtable->u.chain_context3.BacktrackGlyphCount);
1113           dump_coverage_list
1114             (indent, "InputGlyphCount",
1115              subtable->u.chain_context3.Input,
1116              subtable->u.chain_context3.InputGlyphCount);
1117           dump_coverage_list
1118             (indent, "LookaheaGlyphCount",
1119              subtable->u.chain_context3.LookAhead,
1120              subtable->u.chain_context3.LookaheadGlyphCount);
1121           dump_lookup_record_list
1122             (indent,
1123              subtable->u.chain_context3.LookupRecord,
1124              subtable->u.chain_context3.LookupCount);
1125         }
1126       else
1127         printf (" invalid");
1128       break;
1129
1130     case 9:
1131       if (subtable->Format == 1)
1132         {
1133           IPRINT ("(ExtensionLookupType %d)",
1134                   subtable->u.extension1.ExtensionLookupType);
1135           IPRINT ("(ExtensionOffset %d)",
1136                   subtable->u.extension1.ExtensionOffset);
1137           dump_lookup_subtable_gpos
1138             (indent, index, 
1139              subtable->u.extension1.ExtensionLookupType,
1140              subtable->u.extension1.ExtensionSubtable);
1141         }
1142       else
1143         printf (" invalid");
1144     }
1145   printf (")");
1146 }
1147
1148
1149 static void
1150 dump_gpos_table (int indent, OTF_GPOS *gpos)
1151 {
1152   if (! gpos)
1153     return;
1154   IPRINT ("(GPOS");
1155   indent++;
1156   IPRINT ("(Header");
1157   indent++;
1158   IPRINT ("(Version %d.%d)", gpos->Version.high, gpos->Version.low);
1159   IPRINT ("(ScriptList #x%04X)", gpos->ScriptList.offset);
1160   IPRINT ("(FeatureList #x%04X)", gpos->FeatureList.offset);
1161   IPRINT ("(LookupList #x%04X))", gpos->LookupList.offset);
1162   indent--;
1163   dump_script_list (indent, &gpos->ScriptList);
1164   dump_feature_list (indent, &gpos->FeatureList);
1165   dump_lookup_list (indent, &gpos->LookupList, 0);
1166   printf (")");
1167 }
1168
1169 #if 0
1170 static void
1171 dump_base_table (OTF_BASE *base)
1172 {
1173 }
1174
1175 static void
1176 dump_jstf_table (OTF_JSTF *jstf)
1177 {
1178 }
1179 #endif
1180
1181 \f
1182 /* GDEF */
1183 static void
1184 dump_gdef_header (int indent, OTF_GDEFHeader *header)
1185 {
1186   IPRINT ("(Header");
1187   indent++;
1188   IPRINT ("(Version %d.%d)",
1189           header->Version.high, header->Version.low);
1190   IPRINT ("(GlyphClassDef #x%04X)", header->GlyphClassDef);
1191   IPRINT ("(AttachList #x%04X)", header->AttachList);
1192   IPRINT ("(LigCaretList #x%04X)", header->LigCaretList);
1193   IPRINT ("(MarkAttachClassDef #x%04X))",
1194           header->MarkAttachClassDef);
1195 }
1196
1197 static void
1198 dump_attach_list (int indent, OTF_AttachList *list)
1199 {
1200 }
1201
1202 static void
1203 dump_lig_caret_list (int indent, OTF_LigCaretList *list)
1204 {
1205   int i, j;
1206
1207   IPRINT ("(LigCaretList");
1208   indent++;
1209   free (dump_coverage (indent, NULL, &list->Coverage));
1210   IPRINT ("(LigGlyphCount %d)", list->LigGlyphCount);
1211   for (i = 0; i < list->LigGlyphCount; i++)
1212     {
1213       IPRINT ("(LigGlyph (%d) (offset #x%04X)",
1214               i, list->LigGlyph[i].offset);
1215       indent++;
1216       IPRINT ("(CaretCount %d)", list->LigGlyph[i].CaretCount);
1217       for (j = 0; j < list->LigGlyph[i].CaretCount; j++)
1218         {
1219           unsigned format = list->LigGlyph[i].CaretValue[j].CaretValueFormat;
1220
1221           IPRINT ("(Caret (%d) (CaretValueFormat %d)", j, format);
1222           if (format == 1)
1223             {
1224               printf ("(Coordinate %d)",
1225                       list->LigGlyph[i].CaretValue[j].f.f1.Coordinate);
1226             }
1227           else if (format == 2)
1228             {
1229               printf ("(CaretValuePoint %d)",
1230                       list->LigGlyph[i].CaretValue[j].f.f2.CaretValuePoint);
1231             }
1232           else if (format == 3)
1233             {
1234               printf ("(Coodinate %d)",
1235                       list->LigGlyph[i].CaretValue[j].f.f3.Coordinate);
1236               indent++;
1237               dump_device_table
1238                 (indent, "DeviceTable", 
1239                  &list->LigGlyph[i].CaretValue[j].f.f3.DeviceTable);
1240               indent--;
1241             }
1242           printf (")");
1243         }
1244       printf (")");
1245     }
1246   printf (")");
1247 }
1248
1249
1250 static void
1251 dump_gdef_table (int indent, OTF_GDEF *gdef)
1252 {
1253   if (! gdef)
1254     return;
1255   IPRINT ("(GDEF");
1256   indent++;
1257   dump_gdef_header (indent, &gdef->header);
1258   if (gdef->header.GlyphClassDef)
1259     dump_class_def (indent, "GlyphClassDef", &gdef->glyph_class_def);
1260   if (gdef->header.AttachList)
1261     dump_attach_list (indent, &gdef->attach_list);
1262   if (gdef->header.LigCaretList)
1263     dump_lig_caret_list (indent, &gdef->lig_caret_list);
1264   if (gdef->header.MarkAttachClassDef)
1265     dump_class_def (indent, "MarkAttachClassDef",
1266                     &gdef->mark_attach_class_def);
1267   printf (")");
1268 }
1269
1270 \f
1271 /* cmap */
1272 static void
1273 dump_cmap_table (int indent, OTF_cmap *cmap)
1274 {
1275   int i;
1276
1277   IPRINT ("(cmap");
1278   indent++;
1279   IPRINT ("(version %d)", cmap->version);
1280   IPRINT ("(numTables %d)", cmap->numTables);
1281   for (i = 0; i < cmap->numTables; i++)
1282     {
1283       IPRINT ("(EncodingRecord (%d) (platformID %d) (encodingID %d)",
1284               i,
1285               cmap->EncodingRecord[i].platformID,
1286               cmap->EncodingRecord[i].encodingID);
1287       indent++;
1288       IPRINT ("(Subtable (offset #x%04X) (format %d) (length #x%04X) (language %d)",
1289               cmap->EncodingRecord[i].offset,
1290               cmap->EncodingRecord[i].subtable.format,
1291               cmap->EncodingRecord[i].subtable.length,
1292               cmap->EncodingRecord[i].subtable.language);
1293       indent++;
1294       switch (cmap->EncodingRecord[i].subtable.format)
1295         {
1296         case 0:
1297           {
1298             int j, k;
1299             unsigned char *array
1300               = cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray;
1301
1302             IPRINT ("(glyphIdArray");
1303             for (j = 0; j < 16; j++)
1304               {
1305                 IPRINT (" ");
1306                 for (k = 0; k < 16; k++)
1307                   printf (" %3d", array[j * 16 + k]);
1308               }
1309             printf (")");
1310           }
1311           break;
1312
1313         case 4:
1314           {
1315             OTF_EncodingSubtable4 *sub4
1316               = cmap->EncodingRecord[i].subtable.f.f4;
1317             int j;
1318
1319             IPRINT ("(segCountX2 %d) (searchRange %d)",
1320                     sub4->segCountX2, sub4->searchRange);
1321             IPRINT ("(entrySelector %d) (rangeShift %d)",
1322                     sub4->entrySelector, sub4->rangeShift);
1323             for (j = 0; j < sub4->segCountX2 / 2; j++)
1324               {
1325                 IPRINT ("(Segment (%d)", j);
1326                 indent++;
1327                 IPRINT ("(startCount #x%04X) (endCount #x%04X)",
1328                         sub4->segments[j].startCount,
1329                         sub4->segments[j].endCount);
1330                 IPRINT ("(idDelta %d) (idRangeOffset #x%04X))",
1331                         sub4->segments[j].idDelta,
1332                         sub4->segments[j].idRangeOffset);
1333                 indent--;
1334               }
1335             IPRINT ("(glyphIdArray");
1336             for (j = 0; j < sub4->GlyphCount; j++)
1337               {
1338                 if ((j % 16) == 0)
1339                   IPRINT (" ");
1340                 printf (" %3d", sub4->glyphIdArray[j]);
1341               }
1342             printf (")");
1343           }
1344           break;
1345
1346         case 6:
1347           {
1348             OTF_EncodingSubtable6 *sub6
1349               = cmap->EncodingRecord[i].subtable.f.f6;
1350             int j;
1351
1352             IPRINT ("(firstCode %d) (entryCount %d)",
1353                     sub6->firstCode, sub6->entryCount);
1354             IPRINT ("(glyphIdArray");
1355             for (j = 0; j < sub6->entryCount; j++)
1356               {
1357                 if ((j % 16) == 0)
1358                   IPRINT (" ");
1359                 printf (" %3d", sub6->glyphIdArray[j]);
1360               }
1361             printf (")");
1362           }
1363           break;
1364
1365         case 12:
1366           {
1367             OTF_EncodingSubtable12 *sub12
1368               = cmap->EncodingRecord[i].subtable.f.f12;
1369             int j;
1370
1371             for (j = 0; j < sub12->nGroups; j++)
1372               {
1373                 IPRINT ("(Group (#x%X) (startChar #x%04X) (endChar #x%04X) (startGlyphID #x%X))",
1374                         j,
1375                         sub12->Groups[j].startCharCode,
1376                         sub12->Groups[j].endCharCode,
1377                         sub12->Groups[j].startGlyphID);
1378               }
1379           }
1380           break;
1381
1382         case 14:
1383           {
1384             OTF_EncodingSubtable14 *sub14
1385               = cmap->EncodingRecord[i].subtable.f.f14;
1386             unsigned j,k;
1387
1388             IPRINT ("(VariationSelectorRecords %d)",sub14->nRecords);
1389             for (j = 0; j < sub14->nRecords; j++)
1390               {
1391                 OTF_VariationSelectorRecord *record = sub14->Records + j;
1392                 IPRINT ("(VariationSelectorRecord (varSelector #x%x)",
1393                         record->varSelector);
1394                 indent += 1;
1395                 IPRINT ("(defaultUVSOffset #x%x)",
1396                         record->defaultUVSOffset);
1397                 if (record->defaultUVSOffset) 
1398                   {
1399                     IPRINT ("(defaultUVS");
1400                     indent += 1;
1401                     for (k = 0 ; k < record->numUnicodeValueRanges; k++)
1402                       {
1403                         OTF_UnicodeValueRange *unicodeValueRange
1404                           = &record->unicodeValueRanges[k];
1405                         IPRINT("(startUnicodeValue #x%x) (additionalCount %d)",
1406                                unicodeValueRange->startUnicodeValue,
1407                                unicodeValueRange->additionalCount);
1408                       }
1409                     printf (")");
1410                     indent -= 1;
1411                   }
1412                 IPRINT ("(nonDefaultUVSOffset #x%x)",
1413                         record->nonDefaultUVSOffset);
1414                 if (record->nonDefaultUVSOffset) 
1415                   {
1416                     IPRINT ("(NonDefaultUVS");
1417                     indent += 1;
1418                     for (k=0; k < record->numUVSMappings; k++)
1419                       {
1420                         OTF_UVSMapping *uvsMapping
1421                           = &record->uvsMappings[k];
1422                         IPRINT("(unicodeValue #x%x) (glyphID %d)",
1423                                uvsMapping->unicodeValue,
1424                                uvsMapping->glyphID);
1425                       }
1426                     printf (")");
1427                     indent -= 1;
1428                   }
1429                 printf (")");
1430                 indent -= 1;
1431               }
1432           }
1433         }
1434
1435       indent -= 2;
1436       printf ("))");
1437     }
1438   printf (")");
1439 }
1440 \f
1441
1442 /* name */
1443 static void
1444 dump_name_table (int indent, OTF_name *name)
1445 {
1446   int i;
1447
1448   IPRINT ("(name");
1449   indent++;
1450   IPRINT ("(format %d)", name->format);
1451   IPRINT ("(count %d)", name->count);
1452   IPRINT ("(stringOffset %d)", name->stringOffset);
1453   for (i = 0; i < name->count; i++)
1454     {
1455       OTF_NameRecord *rec = name->nameRecord + i; 
1456
1457       IPRINT ("(nameRecord (%d)", i);
1458       indent++;
1459       IPRINT ("(platformID %d) (encodingID %d) (languageID %d) (nameID %d)",
1460               rec->platformID, rec->encodingID, rec->languageID, rec->nameID);
1461       IPRINT ("(length %d) (offset #x%04X))", rec->length, rec->offset);
1462       indent--;
1463     }
1464   for (i = 0; i <= OTF_max_nameID; i++)
1465     if (name->name[i])
1466       IPRINT ("(nameID %d \"%s\")", i, name->name[i]);
1467
1468   printf (")");
1469 }
1470
1471 \f
1472
1473 static void
1474 otf_dump (OTF *otf)
1475 {
1476   int i;
1477
1478   printf ("(OTF");
1479
1480   dump_offset_table (1, &otf->offset_table);
1481   for (i = 0; i < otf->offset_table.numTables; i++)
1482     dump_table_directory (1, otf->table_dirs + i, i);
1483
1484   if (otf->head)
1485     dump_head_table (1, otf->head);
1486   if (otf->name)
1487     dump_name_table (1, otf->name);
1488   if (otf->cmap)
1489     dump_cmap_table (1, otf->cmap);
1490   if (otf->gdef)
1491     dump_gdef_table (1, otf->gdef);
1492   if (otf->gsub)
1493     dump_gsub_table (1, otf->gsub);
1494   if (otf->gpos)
1495     dump_gpos_table (1, otf->gpos);
1496 #if 0
1497   if (otf->base)
1498     dump_base_table (1, otf->base);
1499   if (otf->jstf)
1500     dump_jstf_table (1, otf->jstf);
1501 #endif
1502   printf (")\n");
1503 }
1504
1505
1506 int
1507 main (int argc, char **argv)
1508 {
1509   OTF *otf;
1510
1511   if (argc != 2 || !strcmp (argv[1], "-h") || !strcmp (argv[1], "--help"))
1512     {
1513       fprintf (stderr, "Usage: %s OTF-FILE\n", basename (argv[0]));
1514       exit (argc != 2);
1515     }
1516   
1517   otf = OTF_open (argv[1]);
1518   if (! otf)
1519     {
1520       OTF_perror ("otfdump");
1521       exit (1);
1522     }
1523   OTF_get_table (otf, "head");
1524   OTF_get_table (otf, "name");
1525   OTF_get_table (otf, "cmap");
1526   OTF_get_table (otf, "GDEF");
1527   OTF_get_table (otf, "GSUB");
1528   OTF_get_table (otf, "GPOS");
1529 #if 0
1530   OTF_get_table (otf, "BASE");
1531   OTF_get_table (otf, "JSTF");
1532 #endif
1533   otf_dump (otf);
1534   OTF_close (otf);
1535   exit (0);
1536 }