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