58dbd498b409a1a5edba15fac623f3bbd037078d
[pspp] / dump.c
1 #include <stdbool.h>
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8
9 static uint8_t *data;
10 static size_t n;
11
12 static bool
13 all_ascii(const uint8_t *p, size_t n)
14 {
15   for (size_t i = 0; i < n; i++)
16     if (p[i] < 32 || p[i] > 126)
17       return false;
18   return true;
19 }
20
21 static size_t
22 try_find(const char *target, size_t target_len)
23 {
24   const uint8_t *pos = (const uint8_t *) memmem (data, n, target, target_len);
25   return pos ? pos - data : 0;
26 }
27
28 static size_t
29 try_find_tail(const char *target, size_t target_len)
30 {
31   size_t pos = try_find(target, target_len);
32   return pos ? pos + target_len : 0;
33 }
34
35 static size_t
36 find(const char *target, size_t target_len)
37 {
38   size_t pos = try_find(target, target_len);
39   if (!pos)
40     {
41       fprintf (stderr, "not found\n");
42       exit(1);
43     }
44   return pos;
45 }
46
47 static size_t
48 find_tail(const char *target, size_t target_len)
49 {
50   size_t pos = try_find_tail(target, target_len);
51   if (!pos)
52     {
53       fprintf (stderr, "not found\n");
54       exit(1);
55     }
56   return pos;
57 }
58
59 size_t pos;
60
61 #define XSTR(x) #x
62 #define STR(x) XSTR(x)
63 #define WHERE __FILE__":" STR(__LINE__)
64
65 static unsigned int
66 get_u32(void)
67 {
68   uint32_t x;
69   memcpy(&x, &data[pos], 4);
70   pos += 4;
71   return x;
72 }
73
74 static double
75 get_double(void)
76 {
77   double x;
78   memcpy(&x, &data[pos], 8);
79   pos += 8;
80   return x;
81 }
82
83 static bool
84 match_u32(uint32_t x)
85 {
86   if (get_u32() == x)
87     return true;
88   pos -= 4;
89   return false;
90 }
91
92 static void
93 match_u32_assert(uint32_t x, const char *where)
94 {
95   unsigned int y = get_u32();
96   if (x != y)
97     {
98       fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
99       exit(1);
100     }
101 }
102 #define match_u32_assert(x) match_u32_assert(x, WHERE)
103
104 static bool
105 match_byte(uint8_t b)
106 {
107   if (pos < n && data[pos] == b)
108     {
109       pos++;
110       return true;
111     }
112   else
113     return false;
114 }
115
116 static void
117 match_byte_assert(uint8_t b, const char *where)
118 {
119   if (!match_byte(b))
120     {
121       fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
122       exit(1);
123     }
124 }
125 #define match_byte_assert(b) match_byte_assert(b, WHERE)
126
127 static char *
128 get_string(const char *where)
129 {
130   if (1
131       /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
132       /*&& all_ascii(&data[pos + 4], data[pos])*/)
133     {
134       int len = data[pos] + data[pos + 1] * 256;
135       char *s = malloc(len + 1);
136
137       memcpy(s, &data[pos + 4], len);
138       s[len] = 0;
139       pos += 4 + len;
140       return s;
141     }
142   else
143     {
144       fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
145       exit(1);
146     }
147 }
148 #define get_string() get_string(WHERE)
149
150 static void
151 dump_value(int level)
152 {
153   for (int i = 0; i <= level; i++)
154     printf ("    ");
155
156   match_byte (0);
157   match_byte (0);
158   match_byte (0);
159   match_byte (0);
160   if (match_byte (3))
161     {
162       char *s1 = get_string();
163       if (match_byte (0x31))
164         {
165           if (match_u32 (1))
166             {
167               printf("(footnote %d) ", get_u32());
168               match_byte_assert (0);
169               match_byte_assert (0);
170               int subn = get_u32 ();
171               printf ("nested %d bytes", subn);
172               pos += subn;
173             }
174           else if (match_u32 (2))
175             {
176               printf("(special 2)");
177               match_byte_assert(0);
178               match_byte_assert(0);
179               match_u32_assert(1);
180               match_byte_assert(0);
181               match_byte_assert(0);
182               int subn = get_u32 ();
183               printf ("nested %d bytes", subn);
184               pos += subn;
185             }
186           else
187             {
188               match_u32_assert(3);
189               printf("(special 3)");
190               match_byte_assert(0);
191               match_byte_assert(0);
192               match_byte_assert(1);
193               match_byte_assert(0);
194               int subn = get_u32 ();
195               printf ("nested %d bytes, ", subn);
196               pos += subn;
197               subn = get_u32 ();
198               printf ("nested %d bytes, ", subn);
199               pos += subn;
200             }
201         }
202       else
203         match_byte_assert (0x58);
204       char *s2 = get_string();
205       char *s3 = get_string();
206       if (strcmp(s1, s3))
207         printf("strings \"%s\", \"%s\" and \"%s\"", s1, s2, s3);
208       else
209         printf("string \"%s\" and \"%s\"", s1, s2);
210       match_byte (0);
211       match_byte (0);
212       match_byte (0);
213       match_byte (1);
214       match_byte (1);
215       match_byte (0);
216       match_byte (0);
217       match_byte (0);
218       match_byte (1);
219     }
220   else if (match_byte (5))
221     {
222       match_byte_assert (0x58);
223       printf ("variable \"%s\"", get_string());
224       get_string();
225       if (!match_byte(1) && !match_byte(2))
226         match_byte_assert(3);
227       match_byte (0);
228       match_byte (0);
229       match_byte (0);
230       match_byte (0);
231     }
232   else if (match_byte (2))
233     {
234       unsigned int format;
235       char *var, *vallab;
236       double value;
237
238       match_byte_assert (0x58);
239       format = get_u32 ();
240       value = get_double ();
241       var = get_string ();
242       vallab = get_string ();
243       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
244               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
245       if (!match_byte (1) && !match_byte(2))
246         match_byte_assert (3);
247       match_byte (0);
248       match_byte (0);
249       match_byte (0);
250       match_byte (0);
251       match_byte (0);
252       match_byte (0);
253       match_byte (0);
254     }
255   else if (match_byte (4))
256     {
257       unsigned int format;
258       char *var, *vallab, *value;
259
260       match_byte_assert (0x58);
261       format = get_u32 ();
262       vallab = get_string ();
263       var = get_string ();
264       if (!match_byte(1) && !match_byte(2))
265         match_byte_assert (3);
266       value = get_string ();
267       printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
268               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
269       match_byte (0);
270       match_byte (0);
271       match_byte (0);
272       match_byte (0);
273     }
274   else if (match_byte (1))
275     {
276       unsigned int format;
277       double value;
278
279       if (match_byte (0x31))
280         {
281           if (match_u32 (1))
282             {
283               printf("(footnote %d) ", get_u32());
284               match_byte_assert (0);
285               match_byte_assert (0);
286               int subn = get_u32 ();
287               printf ("nested %d bytes", subn);
288               pos += subn;
289             }
290         }
291       else
292         match_byte_assert (0x58);
293       format = get_u32 ();
294       value = get_double ();
295       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
296       match_byte (1);
297       match_byte (0);
298       match_byte (0);
299       match_byte (0);
300       match_byte (1);
301     }
302   else if (match_byte (0x31))
303     {
304       if (match_u32 (1))
305         {
306           printf("(footnote %d) ", get_u32());
307           match_byte_assert (0);
308           match_byte_assert (0);
309           int subn = get_u32 ();
310           printf ("nested %d bytes", subn);
311           pos += subn;
312         }
313       else
314         {
315           match_u32_assert (0);
316           match_u32_assert (0);
317           int subn = get_u32 ();
318           printf ("nested %d bytes", subn);
319           pos += subn;
320         }
321       char *base = get_string();
322       int x = get_u32();
323       printf ("\"%s\"; %d variables:\n", base, x);
324       if (match_u32(0))
325         {
326           for (int i = 0; i < x; i++)
327             {
328               dump_value (level+1);
329               putchar('\n');
330             }
331         }
332       else
333         {
334           for (int i = 0; i < x; i++)
335             {
336               int y = get_u32();
337               match_u32_assert(0);
338               for (int j = 0; j <= level; j++)
339                 printf ("    ");
340               printf("variable %d has %d values:\n", i, y);
341               for (int j = 0; j < y; j++)
342                 {
343                   if (match_byte(3))
344                     {
345                       char *a = get_string();
346                       match_byte_assert(0x58);
347                       char *b = get_string();
348                       char *c = get_string();
349                       for (int k = 0; k <= level + 1; k++)
350                         printf ("    ");
351                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
352                       match_byte(0);
353                       match_byte(0);
354                       match_byte(0);
355                       match_byte(0);
356                       match_byte(0);
357                     }
358                   else
359                     dump_value (level+1);
360                   putchar('\n');
361                 }
362             }
363         }
364     }
365   else
366     {
367
368       match_byte_assert (0x58);
369       char *base = get_string();
370       int x = get_u32();
371       printf ("\"%s\" with %d variables:\n", base, x);
372       if (match_u32(0))
373         {
374           for (int i = 0; i < x; i++)
375             {
376               dump_value (level+1);
377               putchar('\n');
378             }
379         }
380       else
381         {
382           for (int i = 0; i < x; i++)
383             {
384               int y = get_u32();
385               match_u32_assert(0);
386               for (int j = 0; j <= level; j++)
387                 printf ("    ");
388               printf("variable %d has %d values:\n", i, y);
389               for (int j = 0; j < y; j++)
390                 {
391                   if (match_byte(3))
392                     {
393                       char *a = get_string();
394                       match_byte_assert(0x58);
395                       char *b = get_string();
396                       char *c = get_string();
397                       for (int k = 0; k <= level + 1; k++)
398                         printf ("    ");
399                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
400                       match_byte(0);
401                       match_byte(0);
402                       match_byte(0);
403                       match_byte(0);
404                       match_byte(0);
405                     }
406                   else
407                     dump_value (level+1);
408                   putchar('\n');
409                 }
410             }
411         }
412     }
413 }
414
415 static void
416 dump_dim_value(int level)
417 {
418   for (int i = 0; i <= level; i++)
419     printf ("    ");
420
421   if (match_byte (3))
422     {
423       get_string();
424       if (match_byte (0x31))
425         {
426           match_u32 (1);
427           printf("(footnote %d) ", get_u32());
428           match_byte_assert (0);
429           match_byte_assert (0);
430           int subn = get_u32 ();
431           printf ("nested %d bytes", subn);
432           pos += subn;
433         }
434       else
435         match_byte_assert (0x58);
436       get_string();
437       printf("string \"%s\"", get_string());
438       match_byte (0);
439       match_byte_assert (1);
440       match_byte (0);
441       match_byte (0);
442       match_byte (0);
443       match_byte (1);
444     }
445   else if (match_byte (5))
446     {
447       match_byte_assert (0x58);
448       printf ("variable \"%s\"", get_string());
449       get_string();
450       match_byte_assert (2);
451     }
452   else if (match_byte (2))
453     {
454       unsigned int format;
455       char *var, *vallab;
456       double value;
457
458       match_byte_assert (0x58);
459       format = get_u32 ();
460       value = get_double ();
461       var = get_string ();
462       vallab = get_string ();
463       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
464               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
465       if (!match_u32 (3))
466         match_u32_assert (2);
467       match_byte (0);
468     }
469   else if (match_byte (1))
470     {
471       unsigned int format;
472       double value;
473
474       match_byte_assert (0x58);
475       format = get_u32 ();
476       value = get_double ();
477       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
478       match_byte (1);
479       match_byte (0);
480       match_byte (0);
481       match_byte (0);
482       match_byte (1);
483     }
484   else
485     {
486       int subn;
487
488       match_byte (0);
489       match_byte_assert (0x31);
490       match_u32_assert (0);
491       match_u32_assert (0);
492       subn = get_u32 ();
493       printf ("nested %d bytes", subn);
494       pos += subn;
495       printf ("; \"%s\", substitutions:", get_string());
496       int total_subs = get_u32();
497       int x = get_u32();
498       if (x)
499         {
500           total_subs = (total_subs - 1) + x;
501           match_u32_assert (0);
502         }
503       printf (" (total %d)", total_subs);
504
505       for (int i = 0; i < total_subs; i++)
506         {
507           putc ('\n', stdout);
508           dump_value (level + 1);
509         }
510     }
511 }
512
513 static void
514 dump_category(int level)
515 {
516   match_byte (0);
517   match_byte (0);
518   match_byte (0);
519   match_byte (0);
520   dump_value (level);
521
522   if (match_u32 (2))
523     get_u32 ();
524   else if (match_u32 (1))
525     {
526       match_byte (0);
527       match_byte (0);
528       match_byte (0);
529       get_u32 ();
530     }
531   else if (match_byte (1))
532     {
533       match_byte (0);
534       if (!match_u32 (2))
535         match_u32_assert (1);
536       match_byte (0);
537       get_u32();
538     }
539   else
540     {
541       match_u32_assert (0);
542       get_u32 ();
543     }
544
545   int n_categories = get_u32();
546   if (n_categories > 0)
547     printf (", %d subcategories:", n_categories);
548   printf("\n");
549   for (int i = 0; i < n_categories; i++)
550     dump_category (level + 1);
551 }
552
553 static void
554 dump_dim(void)
555 {
556   int n_categories;
557   printf("next dim\n");
558   match_byte(0);
559   if (match_byte(3))
560     {
561       get_string();
562       match_byte_assert(0x58);
563       get_string();
564       printf("string \"%s\": ", get_string());
565       match_byte(1) || match_byte(0);
566     }
567   else if (match_byte(5)) 
568     {
569       match_byte_assert(0x58);
570       printf("variable \"%s\": ", get_string());
571       get_string();
572       if (!match_byte(2))
573         match_byte_assert(3);
574     }
575   else if (match_byte(0x31))
576     {
577       int subn;
578       int total_subs = 1;
579
580       match_u32_assert (0);
581       match_u32_assert (0);
582       subn = get_u32 ();
583       printf ("nested %d bytes", subn);
584       pos += subn;
585       printf ("; \"%s\", substitutions:", get_string());
586       for (;;)
587         {
588           int n_subst = get_u32();
589           if (!n_subst)
590             break;
591           printf (" %d", n_subst);
592           total_subs *= n_subst;
593         }
594
595       for (int i = 0; i < total_subs; i++)
596         {
597           putc ('\n', stdout);
598           dump_dim_value (0);
599         }
600     }
601   else
602     {
603       int total_subs = 1;
604
605       match_byte_assert (0x58);
606       printf ("\"%s\" with substitutions:", get_string());
607       for (;;)
608         {
609           int n_subst = get_u32();
610           if (!n_subst)
611             break;
612           printf (" %d", n_subst);
613           total_subs *= n_subst;
614         }
615
616       for (int i = 0; i < total_subs; i++)
617         {
618           putc ('\n', stdout);
619           dump_dim_value (0);
620         }
621     }
622
623   /* This byte is usually 0x02 but 0x00 and 0x75 (!) have also been spotted. */
624   pos++;
625
626   if (!match_byte(0) && !match_byte(1))
627     match_byte_assert(2);
628   if (!match_u32(0))
629     match_u32_assert(2);
630   if (!match_byte(0))
631     match_byte_assert(1);
632   match_byte(0);
633   match_byte(0);
634   match_byte(0);
635   match_byte(0);
636   get_u32();
637   match_byte(0);
638   match_byte(0);
639   match_byte(0);
640   match_byte(0);
641   n_categories = get_u32();
642   printf("%d nested categories\n", n_categories);
643   for (int i = 0; i < n_categories; i++)
644     dump_category (0);
645 }
646
647 int n_dims;
648 static void
649 dump_dims(void)
650 {
651   n_dims = get_u32();
652   printf ("%u dimensions\n", n_dims);
653   for (int i = 0; i < n_dims; i++)
654     {
655       printf("\n");
656       dump_dim ();
657     }
658 }
659
660 static void
661 dump_data(void)
662 {
663 #if 1
664   int a[16];
665   for (int i = 0; i < 3 + n_dims; i++)
666     a[i] = get_u32();
667   printf ("data intro:");
668   for (int i = 0; i < 3 + n_dims; i++)
669     printf(" %d", a[i]);
670   printf("\n");
671 #else
672   fprintf (stderr,"data intro (%d dims):", n_dims);
673   for (int i = 0; i < 3+n_dims; i++)
674     fprintf (stderr," %d", get_u32());
675   fprintf(stderr,"\n");
676 #endif
677   int x = get_u32();
678   printf ("%d data values, starting at %08x\n", x, pos);
679   for (int i = 0; i < x; i++)
680     {
681       printf("%08x, index %d:\n", pos, get_u32());
682       match_u32_assert(0);
683       match_byte(0);
684       match_byte(0);
685       match_byte(0);
686       match_byte(0);
687       if (match_byte (1))
688         {
689           unsigned int format;
690           double value;
691
692           if (match_byte (0x31))
693             {
694               if (match_u32 (0))
695                 {
696                   if (match_u32 (1))
697                     get_string();
698                   else
699                     match_u32_assert (0);
700                   int subn = get_u32 ();
701                   printf ("nested %d bytes", subn);
702                   pos += subn;
703                 }
704               else if (match_u32 (1))
705                 {
706                   printf("(footnote %d) ", get_u32());
707                   match_byte_assert (0);
708                   match_byte_assert (0);
709                   int subn = get_u32 ();
710                   printf ("nested %d bytes", subn);
711                   pos += subn;
712                 }
713               else
714                 {
715                   match_u32_assert(2);
716                   printf("(special 2)");
717                   match_byte_assert(0);
718                   match_byte_assert(0);
719                   match_u32_assert(1);
720                   match_byte_assert(0);
721                   match_byte_assert(0);
722                   int subn = get_u32 ();
723                   printf ("nested %d bytes", subn);
724                   pos += subn;
725                 }
726             }
727           else
728             match_byte_assert (0x58);
729           format = get_u32 ();
730           value = get_double ();
731           printf ("    value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
732         }
733       else if (match_byte (3))
734         {
735           get_string();
736           if (match_byte (0x31))
737             {
738               if (match_u32 (0))
739                 {
740                   match_u32_assert (1);
741                   get_string ();
742                   int subn = get_u32 ();
743                   printf ("nested %d bytes", subn);
744                   pos += subn;
745                 }
746               else if (match_u32 (1))
747                 {
748                   printf("(footnote %d) ", get_u32());
749                   match_byte_assert (0);
750                   match_byte_assert (0);
751                   int subn = get_u32 ();
752                   printf ("nested %d bytes", subn);
753                   pos += subn;
754                 }
755               else if (match_u32 (2))
756                 {
757                   printf("(special 2)");
758                   match_byte_assert(0);
759                   match_byte_assert(0);
760                   match_u32_assert(1);
761                   match_byte_assert(0);
762                   match_byte_assert(0);
763                   int subn = get_u32 ();
764                   printf ("nested %d bytes", subn);
765                   pos += subn;
766                 }
767               else
768                 {
769                   match_u32_assert(3);
770                   printf("(special 3)");
771                   match_byte_assert(0);
772                   match_byte_assert(0);
773                   match_byte_assert(1);
774                   match_byte_assert(0);
775                   int subn = get_u32 ();
776                   printf ("nested %d bytes, ", subn);
777                   pos += subn;
778                   subn = get_u32 ();
779                   printf ("nested %d bytes, ", subn);
780                   pos += subn;
781                 }
782             }
783           else
784             match_byte_assert (0x58);
785           get_string();
786           printf("string \"%s\"", get_string());
787           match_byte (0);
788         }
789       else if (match_byte (2))
790         {
791           unsigned int format;
792           char *var, *vallab;
793           double value;
794
795           match_byte_assert (0x58);
796           format = get_u32 ();
797           value = get_double ();
798           var = get_string ();
799           vallab = get_string ();
800           printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
801                   value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
802           if (!match_byte (1) && !match_byte(2))
803             match_byte_assert (3);
804         }
805       else if (match_byte (4))
806         {
807           unsigned int format;
808           char *var, *vallab, *value;
809
810           match_byte_assert (0x58);
811           format = get_u32 ();
812           vallab = get_string ();
813           var = get_string ();
814           if (!match_byte(1) && !match_byte(2))
815             match_byte_assert (3);
816           value = get_string ();
817           printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
818                   value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
819         }
820       else if (match_byte (5))
821         {
822           match_byte_assert (0x58);
823           printf ("variable \"%s\"", get_string());
824           get_string();
825           if (!match_byte(1) && !match_byte(2))
826             match_byte_assert(3);
827           match_byte (0);
828           match_byte (0);
829           match_byte (0);
830           match_byte (0);
831         }
832       else if (match_byte(0x31))
833         {
834           if (match_u32 (1))
835             {
836               printf("(footnote %d) ", get_u32());
837               match_byte_assert (0);
838               match_byte_assert (0);
839               int subn = get_u32 ();
840               printf ("nested %d bytes", subn);
841               pos += subn;
842             }
843           else
844             {
845               match_u32_assert (0);
846               match_u32_assert (0);
847               int subn = get_u32 ();
848               printf ("nested %d bytes", subn);
849               pos += subn;
850             }
851           char *base = get_string();
852           int x = get_u32();
853           printf ("\"%s\"; %d variables:\n", base, x);
854           for (int i = 0; i < x; i++)
855             {
856               int y = get_u32();
857               if (!y)
858                 y = 1;
859               else
860                 match_u32_assert(0);
861               for (int j = 0; j <= 0; j++)
862                 printf ("    ");
863               printf("variable %d has %d values:\n", i, y);
864               for (int j = 0; j < y; j++)
865                 {
866                   if (match_byte (1))
867                     {
868                       unsigned int format;
869                       double value;
870
871                       if (match_byte (0x31))
872                         {
873                           if (match_u32 (0))
874                             {
875                               if (match_u32 (1))
876                                 get_string();
877                               else
878                                 match_u32_assert (0);
879                               int subn = get_u32 ();
880                               printf ("nested %d bytes", subn);
881                               pos += subn;
882                             }
883                           else if (match_u32 (1))
884                             {
885                               printf("(footnote %d) ", get_u32());
886                               match_byte_assert (0);
887                               match_byte_assert (0);
888                               int subn = get_u32 ();
889                               printf ("nested %d bytes", subn);
890                               pos += subn;
891                             }
892                           else
893                             {
894                               match_u32_assert(2);
895                               printf("(special 2)");
896                               match_byte_assert(0);
897                               match_byte_assert(0);
898                               match_u32_assert(1);
899                               match_byte_assert(0);
900                               match_byte_assert(0);
901                               int subn = get_u32 ();
902                               printf ("nested %d bytes", subn);
903                               pos += subn;
904                             }
905                         }
906                       else
907                         match_byte_assert (0x58);
908                       format = get_u32 ();
909                       value = get_double ();
910                       printf ("    value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
911                     }
912                   else if (match_byte(3))
913                     {
914                       char *a = get_string();
915                       match_byte_assert(0x58);
916                       char *b = get_string();
917                       char *c = get_string();
918                       for (int k = 0; k <= 1; k++)
919                         printf ("    ");
920                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
921                       match_byte(0);
922                       match_byte(0);
923                       match_byte(0);
924                       match_byte(0);
925                     }
926                   else if (match_byte(5))
927                     {
928                       match_byte_assert (0x58);
929                       printf ("variable \"%s\"", get_string());
930                       get_string();
931                       if (!match_byte(1) && !match_byte(2))
932                         match_byte_assert(3);
933                       match_byte (0);
934                       match_byte (0);
935                       match_byte (0);
936                       match_byte (0);
937                     }
938                   else
939                     dump_value (0);
940                   putchar('\n');
941                 }
942             }
943         }
944       else
945         {
946           match_byte_assert (0x58);
947           char *base = get_string();
948           int x = get_u32();
949           printf ("\"%s\" with %d variables:\n", base, x);
950           for (int i = 0; i < x; i++)
951             {
952               int y = get_u32();
953               if (!y)
954                 y = 1;
955               else
956                 match_u32_assert(0);
957               for (int j = 0; j <= 0; j++)
958                 printf ("    ");
959               printf("variable %d has %d values:\n", i, y);
960               for (int j = 0; j < y; j++)
961                 {
962                   if (match_byte(3))
963                     {
964                       char *a = get_string();
965                       match_byte_assert(0x58);
966                       char *b = get_string();
967                       char *c = get_string();
968                       for (int k = 0; k <= 1; k++)
969                         printf ("    ");
970                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
971                       match_byte(0);
972                       match_byte(0);
973                       match_byte(0);
974                       match_byte(0);
975                       match_byte(0);
976                     }
977                   else if (match_byte (1))
978                     {
979                       unsigned int format;
980                       double value;
981
982                       if (match_byte (0x31))
983                         {
984                           if (match_u32 (1))
985                             {
986                               printf("(footnote %d) ", get_u32());
987                               match_byte_assert (0);
988                               match_byte_assert (0);
989                               int subn = get_u32 ();
990                               printf ("nested %d bytes", subn);
991                               pos += subn;
992                             }
993                         }
994                       else
995                         match_byte_assert (0x58);
996                       format = get_u32 ();
997                       value = get_double ();
998                       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
999                     }
1000                   else
1001                     dump_value (1);
1002                   putchar('\n');
1003                 }
1004             }
1005         }
1006       putchar('\n');
1007     }
1008 }
1009
1010 static void
1011 dump_title_value(int level)
1012 {
1013   for (int i = 0; i <= level; i++)
1014     printf ("    ");
1015
1016   match_byte (0);
1017   match_byte (0);
1018   match_byte (0);
1019   match_byte (0);
1020   match_byte (0);
1021   if (match_byte (3))
1022     {
1023       get_string();
1024       if (match_byte (0x31))
1025         {
1026           if (match_u32 (1))
1027             {
1028               printf("(footnote %d) ", get_u32());
1029               match_byte_assert (0);
1030               match_byte_assert (0);
1031               int subn = get_u32 ();
1032               printf ("nested %d bytes", subn);
1033               pos += subn;
1034             }
1035           else if (match_u32 (2))
1036             {
1037               printf("(special 2)");
1038               match_byte_assert(0);
1039               match_byte_assert(0);
1040               if (!match_u32(2))
1041                 match_u32_assert(1);
1042               match_byte_assert(0);
1043               match_byte_assert(0);
1044               int subn = get_u32 ();
1045               printf ("nested %d bytes", subn);
1046               pos += subn;
1047             }
1048           else
1049             {
1050               match_u32_assert(3);
1051               printf("(special 3)");
1052               match_byte_assert(0);
1053               match_byte_assert(0);
1054               match_byte_assert(1);
1055               match_byte_assert(0);
1056               int subn = get_u32 ();
1057               printf ("nested %d bytes, ", subn);
1058               pos += subn;
1059               subn = get_u32 ();
1060               printf ("nested %d bytes, ", subn);
1061               pos += subn;
1062             }
1063         }
1064       else
1065         match_byte_assert (0x58);
1066       get_string();
1067       printf("string \"%s\"", get_string());
1068       match_byte (0);
1069       match_byte (0);
1070       match_byte (0);
1071       match_byte (1);
1072       match_byte (1);
1073       match_byte (0);
1074       match_byte (0);
1075       match_byte (0);
1076       match_byte (1);
1077     }
1078   else if (match_byte (5))
1079     {
1080       if (match_byte (0x31))
1081         {
1082           if (match_u32 (1))
1083             {
1084               printf("(footnote %d) ", get_u32());
1085               match_byte_assert (0);
1086               match_byte_assert (0);
1087               int subn = get_u32 ();
1088               printf ("nested %d bytes", subn);
1089               pos += subn;
1090             }
1091         }
1092       else
1093         match_byte_assert (0x58);
1094       printf ("variable \"%s\"", get_string());
1095       get_string();
1096       if (!match_byte(1) && !match_byte(2))
1097         match_byte_assert(3);
1098     }
1099   else if (match_byte (2))
1100     {
1101       unsigned int format;
1102       char *var, *vallab;
1103       double value;
1104
1105       match_byte_assert (0x58);
1106       format = get_u32 ();
1107       value = get_double ();
1108       var = get_string ();
1109       vallab = get_string ();
1110       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
1111               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
1112       if (!match_byte (1) && !match_byte(2))
1113         match_byte_assert (3);
1114       match_byte (0);
1115       match_byte (0);
1116       match_byte (0);
1117       match_byte (0);
1118       match_byte (0);
1119       match_byte (0);
1120       match_byte (0);
1121     }
1122   else if (match_byte (4))
1123     {
1124       unsigned int format;
1125       char *var, *vallab, *value;
1126
1127       match_byte_assert (0x58);
1128       format = get_u32 ();
1129       vallab = get_string ();
1130       var = get_string ();
1131       if (!match_byte(1) && !match_byte(2))
1132         match_byte_assert (3);
1133       value = get_string ();
1134       printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
1135               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
1136       match_byte (0);
1137       match_byte (0);
1138       match_byte (0);
1139       match_byte (0);
1140     }
1141   else if (match_byte (1))
1142     {
1143       unsigned int format;
1144       double value;
1145
1146       if (match_byte (0x31))
1147         {
1148           if (match_u32 (1))
1149             {
1150               printf("(footnote %d) ", get_u32());
1151               match_byte_assert (0);
1152               match_byte_assert (0);
1153               int subn = get_u32 ();
1154               printf ("nested %d bytes", subn);
1155               pos += subn;
1156             }
1157         }
1158       else
1159         match_byte_assert (0x58);
1160       format = get_u32 ();
1161       value = get_double ();
1162       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
1163       match_byte (1);
1164       match_byte (0);
1165       match_byte (0);
1166       match_byte (0);
1167       match_byte (1);
1168     }
1169   else if (match_byte (0x31))
1170     {
1171       if (match_u32 (1))
1172         {
1173           printf("(footnote %d) ", get_u32());
1174           match_byte_assert (0);
1175           match_byte_assert (0);
1176           int subn = get_u32 ();
1177           printf ("nested %d bytes", subn);
1178           pos += subn;
1179         }
1180       else if (match_u32 (0))
1181         {
1182           match_u32_assert (0);
1183           int subn = get_u32 ();
1184           printf ("nested %d bytes", subn);
1185           pos += subn;
1186         }
1187       else
1188         {
1189           match_u32_assert(3);
1190           printf("(special 3)");
1191           match_byte_assert(0);
1192           match_byte_assert(0);
1193           match_byte_assert(1);
1194           match_byte_assert(0);
1195           int subn = get_u32 ();
1196           printf ("nested %d bytes, ", subn);
1197           pos += subn;
1198           subn = get_u32 ();
1199           printf ("nested %d bytes, ", subn);
1200           pos += subn;
1201         }
1202
1203       char *base = get_string();
1204       int x = get_u32();
1205       printf ("\"%s\"; %d variables:\n", base, x);
1206       for (int i = 0; i < x; i++)
1207         {
1208           int y = get_u32();
1209           if (!y)
1210             y = 1;
1211           else
1212             match_u32_assert(0);
1213           for (int j = 0; j <= level; j++)
1214             printf ("    ");
1215           printf("variable %d has %d values:\n", i, y);
1216           for (int j = 0; j < y; j++)
1217             {
1218               if (match_byte(3))
1219                 {
1220                   char *a = get_string();
1221                   match_byte_assert(0x58);
1222                   char *b = get_string();
1223                   char *c = get_string();
1224                   for (int k = 0; k <= level + 1; k++)
1225                     printf ("    ");
1226                   printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
1227                   match_byte(0);
1228                 }
1229               else
1230                 dump_title_value (level+1);
1231               putchar('\n');
1232             }
1233         }
1234     }
1235   else
1236     {
1237       match_byte_assert (0x58);
1238       char *base = get_string();
1239       int x = get_u32();
1240       printf ("\"%s\" with %d variables:\n", base, x);
1241       for (int i = 0; i < x; i++)
1242         {
1243           int y = get_u32();
1244           if (!y)
1245             y = 1;
1246           else
1247             match_u32_assert(0);
1248           for (int j = 0; j <= level; j++)
1249             printf ("    ");
1250           printf("variable %d has %d values:\n", i, y);
1251           for (int j = 0; j < y; j++)
1252             {
1253               match_byte(0);
1254               if (match_byte(3))
1255                 {
1256                   char *a = get_string();
1257                   match_byte_assert(0x58);
1258                   char *b = get_string();
1259                   char *c = get_string();
1260                   for (int k = 0; k <= level + 1; k++)
1261                     printf ("    ");
1262                   printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
1263                 }
1264               else
1265                 dump_title_value (level+1);
1266               putchar('\n');
1267             }
1268         }
1269     }
1270 }
1271
1272 static void
1273 dump_footnote_value(int level)
1274 {
1275   for (int i = 0; i <= level; i++)
1276     printf ("    ");
1277
1278   match_byte (0);
1279   match_byte (0);
1280   match_byte (0);
1281   match_byte (0);
1282   if (match_byte (3))
1283     {
1284       get_string();
1285       if (match_byte (0x31))
1286         {
1287           if (match_u32 (1))
1288             {
1289               printf("(footnote %d) ", get_u32());
1290               match_byte_assert (0);
1291               match_byte_assert (0);
1292               int subn = get_u32 ();
1293               printf ("nested %d bytes", subn);
1294               pos += subn;
1295             }
1296           else if (match_u32 (2))
1297             {
1298               printf("(special 2)");
1299               match_byte_assert(0);
1300               match_byte_assert(0);
1301               match_u32_assert(1);
1302               match_byte_assert(0);
1303               match_byte_assert(0);
1304               int subn = get_u32 ();
1305               printf ("nested %d bytes", subn);
1306               pos += subn;
1307             }
1308           else
1309             {
1310               match_u32_assert(3);
1311               printf("(special 3)");
1312               match_byte_assert(0);
1313               match_byte_assert(0);
1314               match_byte_assert(1);
1315               match_byte_assert(0);
1316               int subn = get_u32 ();
1317               printf ("nested %d bytes, ", subn);
1318               pos += subn;
1319               subn = get_u32 ();
1320               printf ("nested %d bytes, ", subn);
1321               pos += subn;
1322             }
1323         }
1324       else
1325         match_byte_assert (0x58);
1326       get_string();
1327       printf("string \"%s\"", get_string());
1328       if (!match_byte (0))
1329         match_byte_assert (1);
1330     }
1331   else if (match_byte (5))
1332     {
1333       match_byte_assert (0x58);
1334       printf ("variable \"%s\"", get_string());
1335       get_string();
1336       if (!match_byte(1) && !match_byte(2))
1337         match_byte_assert(3);
1338     }
1339   else if (match_byte (2))
1340     {
1341       unsigned int format;
1342       char *var, *vallab;
1343       double value;
1344
1345       match_byte_assert (0x58);
1346       format = get_u32 ();
1347       value = get_double ();
1348       var = get_string ();
1349       vallab = get_string ();
1350       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
1351               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
1352       if (!match_byte (1) && !match_byte(2))
1353         match_byte_assert (3);
1354       match_byte (0);
1355       match_byte (0);
1356       match_byte (0);
1357       match_byte (0);
1358       match_byte (0);
1359       match_byte (0);
1360       match_byte (0);
1361     }
1362   else if (match_byte (4))
1363     {
1364       unsigned int format;
1365       char *var, *vallab, *value;
1366
1367       match_byte_assert (0x58);
1368       format = get_u32 ();
1369       vallab = get_string ();
1370       var = get_string ();
1371       if (!match_byte(1) && !match_byte(2))
1372         match_byte_assert (3);
1373       value = get_string ();
1374       printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
1375               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
1376       match_byte (0);
1377       match_byte (0);
1378       match_byte (0);
1379       match_byte (0);
1380     }
1381   else if (match_byte (1))
1382     {
1383       unsigned int format;
1384       double value;
1385
1386       if (match_byte (0x31))
1387         {
1388           if (match_u32 (1))
1389             {
1390               printf("(footnote %d) ", get_u32());
1391               match_byte_assert (0);
1392               match_byte_assert (0);
1393               int subn = get_u32 ();
1394               printf ("nested %d bytes", subn);
1395               pos += subn;
1396             }
1397         }
1398       else
1399         match_byte_assert (0x58);
1400       format = get_u32 ();
1401       value = get_double ();
1402       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
1403     }
1404   else if (match_byte (0x31))
1405     {
1406       if (match_u32 (1))
1407         {
1408           printf("(footnote %d) ", get_u32());
1409           match_byte_assert (0);
1410           match_byte_assert (0);
1411           int subn = get_u32 ();
1412           printf ("nested %d bytes", subn);
1413           pos += subn;
1414         }
1415       else
1416         {
1417           match_u32_assert (0);
1418           match_u32_assert (0);
1419           int subn = get_u32 ();
1420           printf ("nested %d bytes", subn);
1421           pos += subn;
1422         }
1423       char *base = get_string();
1424       int x = get_u32();
1425       printf ("\"%s\"; %d variables:\n", base, x);
1426       for (int i = 0; i < x; i++)
1427         {
1428           int y = get_u32();
1429           if (!y)
1430             y = 1;
1431           else
1432             match_u32_assert(0);
1433           for (int j = 0; j <= level; j++)
1434             printf ("    ");
1435           printf("variable %d has %d values:\n", i, y);
1436           for (int j = 0; j < y; j++)
1437             {
1438               if (match_byte(3))
1439                 {
1440                   char *a = get_string();
1441                   match_byte_assert(0x58);
1442                   char *b = get_string();
1443                   char *c = get_string();
1444                   for (int k = 0; k <= level + 1; k++)
1445                     printf ("    ");
1446                   printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
1447                   if (!match_byte(1))
1448                     match_byte_assert(0);
1449                 }
1450               else
1451                 dump_footnote_value (level+1);
1452               putchar('\n');
1453             }
1454         }
1455     }
1456   else
1457     {
1458
1459       match_byte_assert (0x58);
1460       char *base = get_string();
1461       int x = get_u32();
1462       printf ("\"%s\" with %d variables:\n", base, x);
1463       for (int i = 0; i < x; i++)
1464         {
1465           int y = get_u32();
1466           if (!y)
1467             y = 1;
1468           else
1469             match_u32_assert(0);
1470           for (int j = 0; j <= level; j++)
1471             printf ("    ");
1472           printf("variable %d has %d values:\n", i, y);
1473           for (int j = 0; j < y; j++)
1474             {
1475               if (match_byte(3))
1476                 {
1477                   char *a = get_string();
1478                   match_byte_assert(0x58);
1479                   char *b = get_string();
1480                   char *c = get_string();
1481                   for (int k = 0; k <= level + 1; k++)
1482                     printf ("    ");
1483                   printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
1484                   match_byte_assert(0);
1485                 }
1486               else
1487                 dump_footnote_value (level+1);
1488               putchar('\n');
1489             }
1490         }
1491     }
1492 }
1493
1494 static void
1495 dump_title(void)
1496 {
1497   pos = 0x27;
1498   dump_title_value(0); putchar('\n');
1499   dump_title_value(0); putchar('\n');
1500   match_byte_assert(0x31);
1501   dump_title_value(0); putchar('\n');
1502   match_byte(0);
1503   match_byte_assert(0x58);
1504   if (match_byte(0x31))
1505     {
1506       dump_footnote_value(0); putchar('\n');
1507     }
1508   else
1509     match_byte_assert(0x58);
1510
1511
1512   int n_footnotes = get_u32();
1513   if (n_footnotes >= 20)
1514     {
1515       fprintf(stderr, "%08x: %d footnotes\n", pos - 4, n_footnotes);
1516       exit(1);
1517     }
1518
1519   printf("------\n%d footnotes\n", n_footnotes);
1520   if (n_footnotes < 20)
1521     {
1522       for (int i = 0; i < n_footnotes; i++)
1523         {
1524           printf("footnote %d:\n", i);
1525           dump_footnote_value(0);
1526           match_byte(0);
1527           match_byte(0);
1528           match_byte(0);
1529           match_byte(0);
1530           if (match_byte (1))
1531             {
1532               unsigned int format;
1533               double value;
1534
1535               if (match_byte (0x31))
1536                 {
1537                   if (match_u32 (1))
1538                     {
1539                       printf("(footnote %d) ", get_u32());
1540                       match_byte_assert (0);
1541                       match_byte_assert (0);
1542                       int subn = get_u32 ();
1543                       printf ("nested %d bytes", subn);
1544                       pos += subn;
1545                     }
1546                 }
1547               else
1548                 match_byte_assert (0x58);
1549               format = get_u32 ();
1550               value = get_double ();
1551               printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
1552               match_byte (1);
1553               match_byte (0);
1554               match_byte (0);
1555               match_byte (0);
1556               match_byte (1);
1557             }
1558           else if (match_byte (0x31))
1559             {
1560               match_byte_assert(3);
1561               get_string();
1562               match_byte_assert(0x58);
1563               match_u32_assert(0);
1564               get_string();
1565               match_byte(0);
1566             }
1567           else
1568             match_byte_assert (0x58);
1569           printf("(%d)\n", get_u32());
1570         }
1571     }
1572 }
1573
1574 static int
1575 find_dimensions(void)
1576 {
1577   {
1578     const char dimensions[] = "-,,,.\0";
1579     int x = try_find_tail(dimensions, sizeof dimensions - 1);
1580     if (x)
1581       return x;
1582   }
1583
1584   const char dimensions[] = "-,,, .\0";
1585   return find_tail(dimensions, sizeof dimensions - 1);
1586 }
1587
1588 static void
1589 dump_fonts(void)
1590 {
1591   printf("fonts: offset=%08x\n", pos);
1592   match_byte(0);
1593   for (int i = 1; i <= 8; i++)
1594     {
1595       printf("%08x: font %d, ", pos, i);
1596       match_byte_assert(i);
1597       match_byte_assert(0x31);
1598       printf("%s, ", get_string());
1599       match_byte_assert(0);
1600       match_byte_assert(0);
1601       if (!match_byte(0x40) && !match_byte(0x20) && !match_byte(0x80) && !match_byte(0x10))
1602         match_byte_assert(0x50);
1603       if (!match_byte(0x41))
1604         match_byte_assert(0x51);
1605       pos += 13;
1606       printf ("%s, ", get_string());
1607       printf ("%s, ", get_string());
1608       match_u32_assert(0);
1609       match_u32_assert(0);
1610       pos++;
1611       get_u32();
1612       get_u32();
1613       get_u32();
1614       get_u32();
1615       putchar('\n');
1616     }
1617
1618   match_u32_assert(240);
1619   pos += 240;
1620
1621   match_u32_assert(18);
1622   pos += 18;
1623
1624   if (match_u32(117))
1625     pos += 117;
1626   else
1627     {
1628       match_u32_assert(142);
1629       pos += 142;
1630     }
1631
1632   int count = get_u32();
1633   pos += 4 * count;
1634
1635   char *encoding = get_string();
1636   printf("encoding=%s\n", encoding);
1637
1638   if (!match_u32(0))
1639     match_u32_assert(UINT32_MAX);
1640   if (!match_byte(0))
1641     match_byte_assert(1);
1642   match_byte_assert(0);
1643   if (!match_byte(0))
1644     match_byte_assert(1);
1645   if (!match_byte(0x99) && !match_byte(0x98))
1646     match_byte_assert(0x97);
1647   match_byte_assert(7);
1648   match_byte_assert(0);
1649   match_byte_assert(0);
1650   if (match_byte('.'))
1651     match_byte_assert(',');
1652   else
1653     {
1654       match_byte_assert(',');
1655       if (!match_byte('.'))
1656         match_byte_assert(' ');
1657     }
1658   match_u32_assert(5);
1659   for (int i = 0; i < 5; i++)
1660     get_string();
1661   pos += get_u32();
1662   if (pos != find_dimensions())
1663     fprintf (stderr, "%08x / %08x\n", pos, find_dimensions());
1664 }
1665
1666 int
1667 main(int argc, char *argv[])
1668 {
1669   size_t start;
1670   struct stat s;
1671
1672   if (isatty(STDIN_FILENO))
1673     {
1674       fprintf(stderr, "redirect stdin from a .bin file\n");
1675       exit(1);
1676     }
1677   if (fstat(STDIN_FILENO, &s))
1678     {
1679       perror("fstat");
1680       exit(1);
1681     }
1682   n = s.st_size;
1683   data = malloc(n);
1684   if (!data)
1685     {
1686       perror("malloc");
1687       exit(1);
1688     }
1689   if (read(STDIN_FILENO, data, n) != n)
1690     {
1691       perror("read");
1692       exit(1);
1693     }
1694
1695   if (argc > 1)
1696     {
1697       if (!strcmp(argv[1], "title0"))
1698         {
1699           pos = 0x27;
1700           if (match_byte (0x03)
1701               || (match_byte (0x05) && match_byte (0x58)))
1702             printf ("%s\n", get_string());
1703           else
1704             printf ("<unknown>\n");
1705           return 0;
1706         }
1707       else if (!strcmp(argv[1], "title"))
1708         {
1709           dump_title();
1710           exit(0);
1711         }
1712       else if (!strcmp(argv[1], "titleraw"))
1713         {
1714           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1715           start = 0x27;
1716           n = find(fonts, sizeof fonts - 1);
1717         }
1718       else if (!strcmp(argv[1], "fonts"))
1719         {
1720           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1721           const char styles[] = "\xf0\0\0\0";
1722           start = find(fonts, sizeof fonts - 1);
1723           n = find(styles, sizeof styles - 1);
1724         }
1725       else if (!strcmp(argv[1], "styles"))
1726         {
1727           const char styles[] = "\xf0\0\0\0";
1728           const char dimensions[] = "-,,,.\0";
1729           start = find(styles, sizeof styles - 1);
1730           n = find(dimensions, sizeof dimensions - 1) + sizeof dimensions - 1;
1731         }
1732       else if (!strcmp(argv[1], "dimensions") || !strcmp(argv[1], "all"))
1733         {
1734           pos = 0;
1735           match_byte_assert(1);
1736           match_byte_assert(0);
1737           match_u32_assert(3);
1738           match_byte_assert(1);
1739           if (!match_byte(0))
1740             match_byte_assert(1);
1741           match_byte_assert(0);
1742           match_byte_assert(0);
1743           if (!match_byte(0))
1744             match_byte_assert(1);
1745           pos++;
1746           match_byte_assert(0);
1747           match_byte_assert(0);
1748           match_byte_assert(0);
1749           dump_title ();
1750           dump_fonts();
1751           dump_dims ();
1752           printf("\n\ndata:\n");
1753           dump_data ();
1754           if (pos == n - 1)
1755             match_byte_assert (1);
1756           if (pos != n)
1757             {
1758               fprintf (stderr, "%x / %x\n", pos, n);
1759               exit(1);
1760             }
1761           exit(0);
1762         }
1763       else
1764         {
1765           fprintf (stderr, "unknown section %s\n", argv[1]);
1766           exit(1);
1767         }
1768     }
1769   else
1770     start = 0x27;
1771
1772   for (size_t i = start; i < n; )
1773     {
1774       if (i + 5 <= n
1775           && data[i]
1776           //&& !data[i + 1]
1777           && !data[i + 2]
1778           && !data[i + 3]
1779           && i + 4 + data[i] + data[i + 1] * 256 <= n
1780           && all_ascii(&data[i + 4], data[i] + data[i + 1] * 256))
1781         {
1782           fputs("\n\"", stdout);
1783           fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stdout);
1784           fputs("\" ", stdout);
1785
1786           i += 4 + data[i] + data[i + 1] * 256;
1787         }
1788       else if (i + 12 <= n
1789                && data[i + 1] == 40
1790                && data[i + 2] == 5
1791                && data[i + 3] == 0)
1792         {
1793           double d;
1794
1795           memcpy (&d, &data[i + 4], 8);
1796           printf ("F40.%d(%.*f)\n", data[i], data[i], d);
1797           i += 12;
1798         }
1799       else if (i + 12 <= n
1800                && data[i + 1] == 40
1801                && data[i + 2] == 31
1802                && data[i + 3] == 0)
1803         {
1804           double d;
1805
1806           memcpy (&d, &data[i + 4], 8);
1807           printf ("PCT40.%d(%.*f)\n", data[i], data[i], d);
1808           i += 12;
1809         }
1810       else if (i + 4 <= n
1811                && (data[i] && data[i] != 88 && data[i] != 0x41)
1812                && !data[i + 1]
1813                && !data[i + 2]
1814                && !data[i + 3])
1815         {
1816           printf ("i%d ", data[i]);
1817           i += 4;
1818         }
1819       else
1820         {
1821           printf("%02x ", data[i]);
1822           i++;
1823         }
1824     }
1825
1826   return 0;
1827 }