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