New
[m17n/libotf.git] / example / otfdump.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7
8 #include <otf.h>
9
10 char *indent_spaces[] =
11   { "", "  ", "    ", "      ", "        ", "          ", "            ",
12     "              ",  "                ",  "                  " };
13
14 /* Indented print.  */
15 #define IPRINT printf("\n%s", indent_spaces[indent]), printf
16
17 static void
18 dump_tag (OTF_Tag tag)
19 {
20   printf ("(tag \"");
21   putchar (tag >> 24);
22   putchar ((tag >> 16) & 0xFF);
23   putchar ((tag >> 8) & 0xFF);
24   putchar (tag & 0xFF);
25   printf ("\" #x%04X)", tag);
26 }
27
28 /* HEAD */
29
30 static void
31 dump_offset_table (int indent, OTF_OffsetTable *table)
32 {
33   IPRINT ("(OffsetTable");
34   indent++;
35   IPRINT ("(sfnt-version %d.%d)", 
36           table->sfnt_version.high, table->sfnt_version.low);
37   IPRINT ("(numTables %d)", table->numTables);
38   IPRINT ("(searchRange %d)", table->searchRange);
39   IPRINT ("(enterSelector %d)", table->enterSelector);
40   IPRINT ("(rangeShift %d))", table->rangeShift);  
41 }
42
43 static void
44 dump_table_directory (int indent, OTF_TableDirectory *table, int idx)
45 {
46   IPRINT ("(Table %d ", idx);
47   dump_tag (table->tag);
48   indent++;
49   IPRINT ("(checkSum %08X) (offset #x%08X) (length: #x%08X))",
50           table->checkSum, table->offset, table->length);
51 }
52
53 \f
54
55 /* head */
56 static void
57 dump_head_table (int indent, OTF_head *head)
58 {
59   int i;
60
61   IPRINT ("(head");
62   indent++;
63   IPRINT ("(TableVersionNumber %d.%d)",
64           head->TableVersionNumber.high, head->TableVersionNumber.low);
65   IPRINT ("(fontRevision %d.%d)",
66           head->fontRevision.high, head->fontRevision.low);
67   IPRINT ("(checkSumAdjustment #x%04X)", head->checkSumAdjustment);
68   IPRINT ("(magicNumber #x%04X)", head->magicNumber);
69   IPRINT ("(flags #x%04X)", head->flags);
70   IPRINT ("(unitsPerEm %d)", head->unitsPerEm);
71   printf (")");
72 }
73
74 \f
75 /* COMMON */
76
77 static void
78 dump_glyph_ids (OTF_GlyphID *ids, unsigned num)
79 {
80   while (num-- > 0)
81     {
82       printf (" #x%04X", *ids);
83       ids++;
84     }
85 }
86
87 static void
88 dump_coverage (int indent, char *title, OTF_Coverage *coverage)
89 {
90   int i;
91
92   IPRINT ("(%sCoverage (CoverageFormat %d)",
93           (title ? title : ""), coverage->CoverageFormat);
94   indent++;
95   if (coverage->CoverageFormat == 1)
96     {
97       IPRINT ("(GlyphCount %d)", coverage->Count);
98       IPRINT ("(GlyphArray");
99       dump_glyph_ids (coverage->table.GlyphArray, coverage->Count);
100       printf (")");
101     }
102   else
103     {
104       IPRINT ("(RangeCount %d)", coverage->Count);
105       indent++;
106       for (i = 0; i < coverage->Count; i++)
107         {
108           IPRINT ("(Range (%d) (Start #x%04X) (End #x%04X)", i,
109                   coverage->table.RangeRecord[i].Start,
110                   coverage->table.RangeRecord[i].End);
111           indent++;
112           IPRINT ("(StartCoverageIndex %d))",
113                   coverage->table.RangeRecord[i].StartCoverageIndex);
114           indent--;
115         }
116     }
117   printf (")");
118 }
119
120 static void
121 dump_coverage_list (int indent, char *title,
122                     OTF_Coverage *coverage, unsigned num)
123 {
124   int i;
125
126   IPRINT ("(%s %d)", title, num);
127   for (i = 0; i < num; i++)
128     dump_coverage (indent, NULL, coverage + i);
129 }
130
131
132 static void
133 dump_language_system (int indent, int index, OTF_Tag tag, OTF_Offset offset,
134                       OTF_LangSys *langsys)
135 {
136   int i;
137
138   IPRINT ("(LangSys ");
139   if (index >= 0)
140     printf ("(%d) ", index);
141   if (tag)
142     dump_tag (tag);
143   else
144     printf ("DefaultLangSys");
145   printf (" (Offset #x%04X)", offset);
146   indent++;
147   IPRINT ("(LookupOrder #x%04X)", langsys->LookupOrder);
148   IPRINT ("(ReqFeatureIndex %d)", langsys->ReqFeatureIndex);
149   IPRINT ("(FeatureCount %d)", langsys->FeatureCount);
150   if (langsys->FeatureCount)
151     {
152       IPRINT ("(FeatureIndex");
153       for (i = 0; i < langsys->FeatureCount; i++)
154         printf (" %d", langsys->FeatureIndex[i]);
155       printf (")");
156     }
157   printf (")");
158 }
159
160 static void
161 dump_script_list (int indent, OTF_ScriptList *list)
162 {
163   int i, j;
164
165   IPRINT ("(ScriptList (count %d)", list->ScriptCount);
166   indent++;
167   for (i = 0; i < list->ScriptCount; i++)
168     {
169       OTF_Script *script = list->Script + i;
170
171       IPRINT ("(Script (%d) ", i);
172       dump_tag (list->ScriptRecord[i].ScriptTag);
173       printf (" (Offset #x%04X)", list->ScriptRecord[i].Script);
174       indent++;
175       IPRINT ("(DefaultLangSysOffset #x%04X)",
176               script->DefaultLangSysOffset);
177       if (script->DefaultLangSysOffset)
178         dump_language_system (indent, -1, 0,
179                               script->DefaultLangSysOffset,
180                               &script->DefaultLangSys);
181       IPRINT ("(LangSysCount %d)", script->LangSysCount);
182       for (j = 0; j < script->LangSysCount; j++)
183         dump_language_system (indent, j,
184                               script->LangSysRecord[j].LangSysTag,
185                               script->LangSysRecord[j].LangSys,
186                               script->LangSys + j);
187       printf (")");
188       indent--;
189     }
190   printf (")");
191 }
192
193 static void
194 dump_feature_list (int indent, OTF_FeatureList *list)
195 {
196   int i, j;
197   
198   IPRINT ("(FeatureList (count %d)", list->FeatureCount);
199   indent++;
200   for (i = 0; i < list->FeatureCount; i++)
201     {
202       OTF_Feature *feature = list->Feature + i;
203
204       IPRINT ("(Feature (%d) ", i);
205       dump_tag (list->FeatureRecord[i].FeatureTag);
206       printf (" (Offset #x%04X)", list->FeatureRecord[i].Feature);
207       printf (" (LookupCount %d)", feature->LookupCount);
208       if (feature->LookupCount)
209         {
210           indent++;
211           IPRINT ("(LookupListIndex");
212           for (j = 0; j < feature->LookupCount; j++)
213             printf (" %d", feature->LookupListIndex[j]);
214           printf (")");
215           indent--;
216         }
217       printf (")");
218     }
219   printf (")");
220 }
221
222 static void
223 dump_class_def (int indent, char *title, OTF_ClassDef *class)
224 {
225   IPRINT ("(%s (offset #x%04X) (ClassFormat %d)",
226           (title ? title : "ClassDef"),
227           class->offset, class->ClassFormat);
228   indent++;
229   if (class->ClassFormat == 1)
230     {
231       IPRINT ("(StartGlyph #x%04X)", class->f.f1.StartGlyph);
232       IPRINT ("(GlyphCount %d)", class->f.f1.GlyphCount);
233       IPRINT ("(ClassValueArray");
234       dump_glyph_ids ((OTF_GlyphID *) class->f.f1.ClassValueArray,
235                       class->f.f1.GlyphCount);
236       printf (")");
237     }
238   else if (class->ClassFormat == 2)
239     {
240       int i;
241
242       IPRINT ("(ClassRangeCount %d)", class->f.f2.ClassRangeCount);
243       IPRINT ("(ClassRangeRecord");
244       indent++;
245       for (i = 0; i < class->f.f2.ClassRangeCount; i++)
246         IPRINT ("((Start #x%04X) (End #x%04X) (class %d))",
247                 class->f.f2.ClassRangeRecord[i].Start,
248                 class->f.f2.ClassRangeRecord[i].End,
249                 class->f.f2.ClassRangeRecord[i].Class);
250       printf (")");
251     }
252   else
253     printf ("UknownClassFormat");
254   printf (")");
255 }
256
257 static void
258 dump_device_table (int indent, char *title, OTF_DeviceTable *table)
259 {
260   int i;
261
262   if (! table->offset)
263     return;
264   IPRINT ("(%s (offset #x%04X)", title, table->offset);
265   indent++;
266   IPRINT ("(StartSize %d) (EndSize %d) (DeltaFormat %d)",
267           table->StartSize, table->EndSize, table->DeltaFormat);
268   IPRINT ("(DeltaValue");
269   for (i = 0; i < table->EndSize - table->StartSize + 1; i++)
270     printf (" %d", table->DeltaValue[i]);
271   printf ("))");
272 }
273
274 \f
275
276 static void
277 dump_value_record (int indent, char *title, OTF_ValueRecord *rec)
278 {
279   IPRINT ("(%s %d %d %d %d", title,
280           rec->XPlacement, rec->YPlacement, rec->XAdvance, rec->YAdvance);
281   indent++;
282   if (rec->XPlaDevice.offset)
283     dump_device_table (indent, "XPlaDevice", &rec->XPlaDevice);
284   if (rec->YPlaDevice.offset)
285     dump_device_table (indent, "YPlaDevice", &rec->YPlaDevice);
286   if (rec->XAdvDevice.offset)
287     dump_device_table (indent, "XAdvDevice", &rec->XAdvDevice);
288   if (rec->YAdvDevice.offset)
289     dump_device_table (indent, "YAdvDevice", &rec->YAdvDevice);
290   printf (")");
291 }
292
293
294 static void
295 dump_sequence_list (int indent, OTF_Sequence *sequence, unsigned num)
296 {
297   int i;
298   IPRINT ("(SequenceCount %d)", num);
299
300   for (i = 0; i < num; i++)
301     {
302       IPRINT ("(Sequence (%d) (offset #x%04X)",
303               i, sequence[i].offset);
304       indent++;
305       IPRINT ("(GlyphCount %d)", sequence[i].GlyphCount);
306       IPRINT ("(Substitute");
307       dump_glyph_ids (sequence[i].Substitute, sequence[i].GlyphCount);
308       printf ("))");
309       indent--;
310     }
311 }
312
313 static void
314 dump_ligature_set_list (int indent, OTF_LigatureSet *ligset, unsigned num)
315 {
316   int i, j;
317
318   IPRINT ("(LigSetCount %d)", num);
319   for (i = 0; i < num; i++)
320     {
321       IPRINT ("(LigatureSet (%d) (offset #x%04X) (count %d)",
322               i, ligset[i].offset, ligset[i].LigatureCount);
323       indent++;
324       for (j = 0; j < ligset[i].LigatureCount; j++)
325         {
326           IPRINT ("(Ligature (%d) (offset #x%04X)",
327                   j, ligset[i].Ligature[j].offset);
328           indent++;
329           IPRINT ("(LigGlyph #x%04X)",
330                   ligset[i].Ligature[j].LigGlyph);
331           IPRINT ("(ComCount %d)",
332                   ligset[i].Ligature[j].CompCount);
333           IPRINT ("(Component");
334           dump_glyph_ids (ligset[i].Ligature[j].Component,
335                           ligset[i].Ligature[j].CompCount - 1);
336           printf ("))");
337           indent--;
338         }
339       indent--;
340       printf (")");
341     }
342 }
343
344 static void
345 dump_class1_record_list (int indent,
346                          unsigned Class1Count, unsigned Class2Count,
347                          OTF_Class1Record *rec)
348 {
349   int i, j;
350
351   for (i = 0; i < Class1Count; i++)
352     {
353       IPRINT ("(Class1Record (%d)", i);
354       indent++;
355       for (j = 0; j < Class2Count; j++)
356         {
357           IPRINT ("(Class2Record (%d)", j);
358           indent++;
359           dump_value_record (indent, "Value1", &rec[i].Class2Record[j].Value1);
360           dump_value_record (indent, "Value2", &rec[i].Class2Record[j].Value2);
361           printf (")");
362           indent--;
363         }
364       printf (")");
365       indent--;
366     }
367 }
368
369 static void
370 dump_anchor (int indent, OTF_Anchor *anchor)
371 {
372   IPRINT ("(Anchor (offset #x%04X) (AnchorFormat %d)",
373           anchor->offset, anchor->AnchorFormat);
374   indent++;
375   IPRINT ("(XCoordinate %d) (YCoordinate %d)",
376           anchor->XCoordinate, anchor->YCoordinate);
377   if (anchor->AnchorFormat == 1)
378     ;
379   else if (anchor->AnchorFormat == 2)
380     IPRINT ("(AnchorPoint %d)", anchor->f.f1.AnchorPoint);
381   else
382     {
383       dump_device_table (indent, "XDeviceTable", &anchor->f.f2.XDeviceTable);
384       dump_device_table (indent, "YDeviceTable", &anchor->f.f2.YDeviceTable);
385     }
386   printf (")");
387 }
388
389 static void
390 dump_mark_array (int indent, OTF_MarkArray *array)
391 {
392   int i;
393
394   IPRINT ("(MarkArray (MarkCount %d)", array->MarkCount);
395   indent++;
396   for (i = 0; i < array->MarkCount; i++)
397     {
398       IPRINT ("(MarkRecord (%d) (Class %d)", i, array->MarkRecord[i].Class);
399       dump_anchor (indent + 1, &array->MarkRecord[i].MarkAnchor);
400       printf (")");
401     }
402   printf (")");
403 }
404
405 static void
406 dump_base_array (int indent, unsigned ClassCount, OTF_BaseArray *array)
407 {
408   int i, j;
409
410   IPRINT ("(BaseArray (BaseCount %d)", array->BaseCount);
411   indent++;
412   for (i = 0; i < array->BaseCount; i++)
413     {
414       IPRINT ("(BaseRecord (%d) ", i);
415       for (j = 0; j < ClassCount; j++)
416         dump_anchor (indent + 1, array->BaseRecord[i].BaseAnchor + j);
417       printf (")");
418     }
419   printf (")");
420 }
421
422
423 static void
424 dump_subst_lookup_record_list (int indent,
425                                OTF_SubstLookupRecord *rec, unsigned num)
426 {
427   int i;
428
429   IPRINT ("(SubstCount %d)", num);
430   for (i = 0; i < num; i++)
431     {
432       IPRINT ("(SubstLookupRecord (%d)", i);
433       indent++;
434       IPRINT ("(SequenceIndex %d)", rec[i].SequenceIndex);
435       IPRINT ("(LookupListIndex %d))", rec[i].LookupListIndex);
436       indent--;
437     }
438 }
439
440
441 static void dump_lookup_subtable_gsub (int indent, int index, unsigned type,
442                                        OTF_LookupSubTable *subtable);
443 static void dump_lookup_subtable_gpos (int indent, int index, unsigned type,
444                                        OTF_LookupSubTable *subtable);
445
446
447 static void
448 dump_lookup_list (int indent, OTF_LookupList *list, int gsub)
449 {
450   int i, j;
451
452   IPRINT ("(LookupList (count %d)", list->LookupCount);
453   indent++;
454   for (i = 0; i < list->LookupCount; i++)
455     {
456       OTF_Lookup *lookup = list->Lookup + i;
457
458       IPRINT ("(Lookup (%d) (Offset #x%04X)",
459               i, list->LookupOffset[i]);
460       printf (" (Type %d) (Flag #x%04X) (SubTableCount %d)",
461               lookup->LookupType, lookup->LookupFlag, lookup->SubTableCount);
462       if (gsub)
463         for (j = 0; j < lookup->SubTableCount; j++)
464           dump_lookup_subtable_gsub (indent + 1, j,
465                                      lookup->LookupType, lookup->SubTable + j);
466       else
467         for (j = 0; j < lookup->SubTableCount; j++)
468           dump_lookup_subtable_gpos (indent + 1, j,
469                                      lookup->LookupType, lookup->SubTable + j);
470
471       printf (")");
472     }
473   printf (")");
474 }
475
476
477 \f
478 /* GSUB */
479 static void
480 dump_gsub_header (int indent, OTF_GSUBHeader *header)
481 {
482   IPRINT ("(Header");
483   indent++;
484   IPRINT ("(Version %d.%d)",
485           header->Version.high, header->Version.low);
486   IPRINT ("(ScriptList #x%04X)", header->ScriptList);
487   IPRINT ("(FeatureList #x%04X)", header->FeatureList);
488   IPRINT ("(LookupList #x%04X))", header->LookupList);
489 }
490
491
492 static void
493 dump_lookup_subtable_gsub (int indent, int index, unsigned type,
494                            OTF_LookupSubTable *subtable)
495 {
496   IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format);
497   indent++;
498   switch (type)
499     {
500     case 1:
501       if (subtable->Format == 1)
502         {
503           dump_coverage (indent, NULL, &subtable->Coverage);
504           IPRINT ("(DeltaGlyhpID #x%04X)",
505                   subtable->sub.gsub.single1.DeltaGlyphID);
506         }
507       else if (subtable->Format == 2)
508         {
509           dump_coverage (indent, NULL, &subtable->Coverage);
510           IPRINT ("(GlyphCount %d)",
511                   subtable->sub.gsub.single2.GlyphCount);
512           IPRINT ("(Substitute");
513           dump_glyph_ids (subtable->sub.gsub.single2.Substitute,
514                           subtable->sub.gsub.single2.GlyphCount);
515           printf (")");
516         }
517       break;
518
519     case 2:
520       if (subtable->Format == 1)
521         {
522           dump_coverage (indent, NULL, &subtable->Coverage);
523           dump_sequence_list (indent,
524                               subtable->sub.gsub.multiple1.Sequence,
525                               subtable->sub.gsub.multiple1.SequenceCount);
526         }
527       break;
528       
529     case 4:
530       if (subtable->Format == 1)
531         {
532           dump_coverage (indent, NULL, &subtable->Coverage);
533           dump_ligature_set_list (indent,
534                                   subtable->sub.gsub.ligature1.LigatureSet,
535                                   subtable->sub.gsub.ligature1.LigSetCount);
536         }
537       break;
538
539     case 6:
540       if (subtable->Format == 1)
541         {
542 #if 0
543           read_coverage (fp, offset,
544                          &subtable->sub.gsub.chain_context1.Coverage);
545           subtable->sub.gsub.chain_context1.ChainSubRuleSetCount
546             = (read_chain_subrule_set
547                (fp, offset,
548                 &subtable->sub.gsub.chain_context1.ChainSubRuleSet));
549 #endif
550         }
551       else if (subtable->Format == 2)
552         {
553 #if 0
554           read_coverage (fp, offset,
555                          &subtable->sub.gsub.chain_context2.Coverage);
556           read_class_def (fp, offset,
557                           &subtable->sub.gsub.chain_context2.Backtrack);
558           read_class_def (fp, offset,
559                           &subtable->sub.gsub.chain_context2.Input);
560           read_class_def (fp, offset,
561                           &subtable->sub.gsub.chain_context2.LookAhead);
562           subtable->sub.gsub.chain_context2.ChainSubClassSetCnt
563             = (read_chain_subclass_set
564                (fp, offset,
565                 &subtable->sub.gsub.chain_context2.ChainSubClassSet));
566 #endif
567         }
568       else if (subtable->Format == 3)
569         {
570           dump_coverage_list
571             (indent, "BackTrackGlyphCount",
572              subtable->sub.gsub.chain_context3.Backtrack,
573              subtable->sub.gsub.chain_context3.BacktrackGlyphCount);
574           dump_coverage_list
575             (indent, "InputGlyphCount",
576              subtable->sub.gsub.chain_context3.Input,
577              subtable->sub.gsub.chain_context3.InputGlyphCount);
578           dump_coverage_list
579             (indent, "LookaheaGlyphCount",
580              subtable->sub.gsub.chain_context3.LookAhead,
581              subtable->sub.gsub.chain_context3.LookaheadGlyphCount);
582           dump_subst_lookup_record_list
583             (indent,
584              subtable->sub.gsub.chain_context3.SubstLookupRecord,
585              subtable->sub.gsub.chain_context3.SubstCount);
586         }
587       break;
588     }
589   printf (")");
590 }
591
592 static void
593 dump_gsub_table (int indent, OTF_GSUB *gsub)
594 {
595   IPRINT ("(GSUB");
596   indent++;
597   dump_gsub_header (indent, &gsub->header);
598   dump_script_list (indent, &gsub->script_list);
599   dump_feature_list (indent, &gsub->feature_list);
600   dump_lookup_list (indent, &gsub->lookup_list, 1);
601   printf (")");
602 }
603
604 \f
605 /* GPOS */
606
607 static void
608 dump_lookup_subtable_gpos (int indent, int index, unsigned type,
609                            OTF_LookupSubTable *subtable)
610 {
611   IPRINT ("(SubTable (%d) (Format %d)", index, subtable->Format);
612   indent++;
613   switch (type)
614     {
615     case 1:
616 #if 0
617       if (subtable->Format == 1)
618         {
619           dump_coverage (indent, NULL, &subtable->sub.gpos.single1.Coverage);
620           IPRINT ("(DeltaGlyhpID #x%04X)",
621                   subtable->sub.gsub.single1.DeltaGlyphID);
622         }
623       else if (subtable->Format == 2)
624         {
625           dump_coverage (indent, NULL, &subtable->sub.gsub.single2.Coverage);
626           IPRINT ("(GlyphCount %d)",
627                   subtable->sub.gsub.single2.GlyphCount);
628           IPRINT ("(Substitute");
629           dump_glyph_ids (subtable->sub.gsub.single2.Substitute,
630                           subtable->sub.gsub.single2.GlyphCount);
631           printf (")");
632         }
633 #endif
634       break;
635
636     case 2:
637       if (subtable->Format == 1)
638         {
639           dump_coverage (indent, NULL, &subtable->Coverage);
640         }
641       else if (subtable->Format == 2)
642         {
643           dump_coverage (indent, NULL, &subtable->Coverage);
644           IPRINT ("(ValueFormat1 #x%04X)",
645                   subtable->sub.gpos.pair2.ValueFormat1);
646           IPRINT ("(ValueFormat2 #x%04X)",
647                   subtable->sub.gpos.pair2.ValueFormat2);
648           dump_class_def (indent, "ClassDef1",
649                           &subtable->sub.gpos.pair2.ClassDef1);
650           dump_class_def (indent, "ClassDef2",
651                           &subtable->sub.gpos.pair2.ClassDef2);
652           IPRINT ("(Class1Count %d)",
653                   subtable->sub.gpos.pair2.Class1Count);
654           IPRINT ("(Class2Count %d)",
655                   subtable->sub.gpos.pair2.Class2Count);
656           dump_class1_record_list (indent,
657                                    subtable->sub.gpos.pair2.Class1Count,
658                                    subtable->sub.gpos.pair2.Class2Count,
659                                    subtable->sub.gpos.pair2.Class1Record);
660         }
661       break;
662       
663     case 4:
664       if (subtable->Format == 1)
665         {
666           dump_coverage (indent, "Mark", &subtable->Coverage);
667           dump_coverage (indent, "Base",
668                          &subtable->sub.gpos.mark_base1.BaseCoverage);
669           IPRINT ("(ClassCount %d)",
670                   subtable->sub.gpos.mark_base1.ClassCount);
671           dump_mark_array (indent, &subtable->sub.gpos.mark_base1.MarkArray);
672           dump_base_array (indent, subtable->sub.gpos.mark_base1.ClassCount,
673                            &subtable->sub.gpos.mark_base1.BaseArray);
674         }
675       break;
676
677     case 6:
678       if (subtable->Format == 1)
679         {
680 #if 0
681           read_coverage (fp, offset,
682                          &subtable->sub.gsub.chain_context1.Coverage);
683           subtable->sub.gsub.chain_context1.ChainSubRuleSetCount
684             = (read_chain_subrule_set
685                (fp, offset,
686                 &subtable->sub.gsub.chain_context1.ChainSubRuleSet));
687 #endif
688         }
689       else if (subtable->Format == 2)
690         {
691 #if 0
692           read_coverage (fp, offset,
693                          &subtable->sub.gsub.chain_context2.Coverage);
694           read_class_def (fp, offset,
695                           &subtable->sub.gsub.chain_context2.Backtrack);
696           read_class_def (fp, offset,
697                           &subtable->sub.gsub.chain_context2.Input);
698           read_class_def (fp, offset,
699                           &subtable->sub.gsub.chain_context2.LookAhead);
700           subtable->sub.gsub.chain_context2.ChainSubClassSetCnt
701             = (read_chain_subclass_set
702                (fp, offset,
703                 &subtable->sub.gsub.chain_context2.ChainSubClassSet));
704 #endif
705         }
706       else if (subtable->Format == 3)
707         {
708 #if 0
709           dump_coverage_list
710             (indent, "BackTrackGlyphCount",
711              subtable->sub.gsub.chain_context3.Backtrack,
712              subtable->sub.gsub.chain_context3.BacktrackGlyphCount);
713           dump_coverage_list
714             (indent, "InputGlyphCount",
715              subtable->sub.gsub.chain_context3.Input,
716              subtable->sub.gsub.chain_context3.InputGlyphCount);
717           dump_coverage_list
718             (indent, "LookaheaGlyphCount",
719              subtable->sub.gsub.chain_context3.LookAhead,
720              subtable->sub.gsub.chain_context3.LookaheadGlyphCount);
721           dump_subst_lookup_record_list
722             (indent,
723              subtable->sub.gsub.chain_context3.SubstLookupRecord,
724              subtable->sub.gsub.chain_context3.SubstCount);
725 #endif
726         }
727       break;
728     }
729   printf (")");
730 }
731
732
733 static void
734 dump_gpos_table (int indent, OTF_GPOS *gpos)
735 {
736   IPRINT ("(GPOS");
737   indent++;
738   dump_gsub_header (indent, (OTF_GPOSHeader *) &gpos->header);
739   dump_script_list (indent, &gpos->script_list);
740   dump_feature_list (indent, &gpos->feature_list);
741   dump_lookup_list (indent, &gpos->lookup_list, 0);
742   printf (")");
743 }
744
745 #if 0
746 static void
747 dump_base_table (OTF_BASE *base)
748 {
749 }
750
751 static void
752 dump_jstf_table (OTF_JSTF *jstf)
753 {
754 }
755 #endif
756
757 \f
758 /* GDEF */
759 static void
760 dump_gdef_header (int indent, OTF_GDEFHeader *header)
761 {
762   IPRINT ("(Header\n");
763   indent++;
764   IPRINT ("(Version %d.%d)",
765           header->Version.high, header->Version.low);
766   IPRINT ("(GlyphClassDef #x%04X)", header->GlyphClassDef);
767   IPRINT ("(AttachList #x%04X)", header->AttachList);
768   IPRINT ("(LigCaretList #x%04X)", header->LigCaretList);
769   IPRINT ("(MarkAttachClassDef #x%04X))",
770           header->MarkAttachClassDef);
771 }
772
773 static void
774 dump_attach_list (int indent, OTF_AttachList *list)
775 {
776 }
777
778 static void
779 dump_lig_caret_list (int indent, OTF_LigCaretList *list)
780 {
781   int i, j;
782
783   IPRINT ("(LigCaretList");
784   indent++;
785   dump_coverage (indent, NULL, &list->Coverage);
786   IPRINT ("(LigGlyphCount %d)", list->LigGlyphCount);
787   for (i = 0; i < list->LigGlyphCount; i++)
788     {
789       IPRINT ("(LigGlyph (%d) (offset #x%04X)",
790               i, list->LigGlyph[i].offset);
791       indent++;
792       IPRINT ("(CaretCount %d)", list->LigGlyph[i].CaretCount);
793       for (j = 0; j < list->LigGlyph[i].CaretCount; j++)
794         {
795           unsigned format = list->LigGlyph[i].CaretValue[j].CaretValueFormat;
796
797           IPRINT ("(Caret (%d) (CaretValueFormat %d)", j, format);
798           if (format == 1)
799             {
800               printf ("(Coordinate %d)",
801                       list->LigGlyph[i].CaretValue[j].f.f1.Coordinate);
802             }
803           else if (format == 2)
804             {
805               printf ("(CaretValuePoint %d)",
806                       list->LigGlyph[i].CaretValue[j].f.f2.CaretValuePoint);
807             }
808           else if (format == 3)
809             {
810               printf ("(Coodinate %d)",
811                       list->LigGlyph[i].CaretValue[j].f.f3.Coordinate);
812               indent++;
813               dump_device_table
814                 (indent, "DeviceTable", 
815                  &list->LigGlyph[i].CaretValue[j].f.f3.DeviceTable);
816               indent--;
817             }
818           printf (")");
819         }
820       printf (")");
821     }
822   printf (")");
823 }
824
825
826 static void
827 dump_gdef_table (int indent, OTF_GDEF *gdef)
828 {
829   IPRINT ("(GDEF");
830   indent++;
831   dump_gdef_header (indent, &gdef->header);
832   if (gdef->header.GlyphClassDef)
833     dump_class_def (indent, "GlyphClassDef", &gdef->glyph_class_def);
834   if (gdef->header.AttachList)
835     dump_attach_list (indent, &gdef->attach_list);
836   if (gdef->header.LigCaretList)
837     dump_lig_caret_list (indent, &gdef->lig_caret_list);
838   if (gdef->header.MarkAttachClassDef)
839     dump_class_def (indent, "MarkAttachClassDef",
840                     &gdef->mark_attach_class_def);
841   printf (")");
842 }
843
844 \f
845 /* cmap */
846 static void
847 dump_cmap_table (int indent, OTF_cmap *cmap)
848 {
849   int i;
850
851   IPRINT ("(cmap");
852   indent++;
853   IPRINT ("(version %d)", cmap->version);
854   IPRINT ("(numTables %d)", cmap->numTables);
855   for (i = 0; i < cmap->numTables; i++)
856     {
857       IPRINT ("(EncodingRecord (%d) (platformID %d) (encodingID %d)",
858               i,
859               cmap->EncodingRecord[i].platformID,
860               cmap->EncodingRecord[i].encodingID);
861       indent++;
862       IPRINT ("(Subtable (offset #x%04X) (format %d) (length #x%04X) (language %d)",
863               cmap->EncodingRecord[i].offset,
864               cmap->EncodingRecord[i].subtable.format,
865               cmap->EncodingRecord[i].subtable.length,
866               cmap->EncodingRecord[i].subtable.language);
867       indent++;
868       switch (cmap->EncodingRecord[i].subtable.format)
869         {
870         case 0:
871           {
872             int j, k;
873             unsigned char *array
874               = cmap->EncodingRecord[i].subtable.f.f0->glyphIdArray;
875
876             IPRINT ("(glyphIdArray");
877             for (j = 0; j < 16; j++)
878               {
879                 IPRINT (" ");
880                 for (k = 0; k < 16; k++)
881                   printf (" %3d", array[j * 16 + k]);
882               }
883             printf (")");
884           }
885           break;
886
887         case 4:
888           {
889             OTF_EncodingSubtable4 *sub4
890               = cmap->EncodingRecord[i].subtable.f.f4;
891             int j;
892
893             IPRINT ("(segCountX2 %d) (searchRange %d)",
894                     sub4->segCountX2, sub4->searchRange);
895             IPRINT ("(entrySelector %d) (rangeShift %d)",
896                     sub4->entrySelector, sub4->rangeShift);
897             for (j = 0; j < sub4->segCountX2 / 2; j++)
898               {
899                 IPRINT ("(Segment (%d)", j);
900                 indent++;
901                 IPRINT ("(startCount #x%04X) (endCount #x%04X)",
902                         sub4->segments[j].startCount,
903                         sub4->segments[j].endCount);
904                 IPRINT ("(idDelta %d) (idRangeOffset #x%04X))",
905                         sub4->segments[j].idDelta,
906                         sub4->segments[j].idRangeOffset);
907                 indent--;
908               }
909             IPRINT ("(glyphIdArray");
910             for (j = 0; j < sub4->GlyphCount; j++)
911               {
912                 if ((j % 16) == 0)
913                   IPRINT (" ");
914                 printf (" %3d", sub4->glyphIdArray[j]);
915               }
916             printf (")");
917           }
918           break;
919         }
920
921       indent -= 2;
922       printf ("))");
923     }
924   printf (")");
925 }
926 \f
927
928 /* name */
929 static void
930 dump_name_table (int indent, OTF_name *name)
931 {
932   int i;
933
934   IPRINT ("(name");
935   indent++;
936   IPRINT ("(format %d)", name->format);
937   IPRINT ("(count %d)", name->count);
938   IPRINT ("(stringOffset %d)", name->stringOffset);
939   for (i = 0; i < name->count; i++)
940     {
941       OTF_NameRecord *rec = name->nameRecord + i; 
942
943       IPRINT ("(nameRecord (%d)", i);
944       indent++;
945       IPRINT ("(platformID %d) (encodingID %d) (languageID %d) (nameID %d)",
946               rec->platformID, rec->encodingID, rec->languageID, rec->nameID);
947       IPRINT ("(length %d) (offset #x%04X))", rec->length, rec->offset);
948       indent--;
949     }
950   for (i = 0; i <= OTF_max_nameID; i++)
951     if (name->name[i])
952       IPRINT ("(nameID %d \"%s\")", i, name->name[i]);
953
954   printf (")");
955 }
956
957 \f
958
959 static void
960 otf_dump (OTF *otf)
961 {
962   int i;
963
964   printf ("(OTF");
965   dump_offset_table (1, &otf->offset_table);
966   for (i = 0; i < otf->offset_table.numTables; i++)
967     dump_table_directory (1, otf->table_dirs + i, i);
968   if (otf->head)
969     dump_head_table (1, otf->head);
970   if (otf->name)
971     dump_name_table (1, otf->name);
972   if (otf->cmap)
973     dump_cmap_table (1, otf->cmap);
974   if (otf->gdef)
975     dump_gdef_table (1, otf->gdef);
976   if (otf->gsub)
977     dump_gsub_table (1, otf->gsub);
978   if (otf->gpos)
979     dump_gpos_table (1, otf->gpos);
980 #if 0
981   if (otf->base)
982     dump_base_table (otf->base);
983   if (otf->jstf)
984     dump_jstf_table (otf->jstf);
985 #endif
986   printf (")\n");
987 }
988
989
990 int
991 main (int argc, char **argv)
992 {
993   OTF *otf;
994
995   if (argc != 2)
996     {
997       fprintf (stderr, "Usage, dtfdump OTF-FILE");
998       exit (1);
999     }
1000   
1001   otf = otf_open (argv[1]);
1002   otf_dump (otf);
1003   otf_close (otf);
1004   exit (0);
1005 }