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