Fix some more--only one error remains!
[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 (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       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       get_string();
205       printf("string \"%s\"", get_string());
206       match_byte (0);
207       match_byte (0);
208       match_byte (0);
209       match_byte (1);
210       match_byte (1);
211       match_byte (0);
212       match_byte (0);
213       match_byte (0);
214       match_byte (1);
215     }
216   else if (match_byte (5))
217     {
218       match_byte_assert (0x58);
219       printf ("variable \"%s\"", get_string());
220       get_string();
221       if (!match_byte(1) && !match_byte(2))
222         match_byte_assert(3);
223       match_byte (0);
224       match_byte (0);
225       match_byte (0);
226       match_byte (0);
227     }
228   else if (match_byte (2))
229     {
230       unsigned int format;
231       char *var, *vallab;
232       double value;
233
234       match_byte_assert (0x58);
235       format = get_u32 ();
236       value = get_double ();
237       var = get_string ();
238       vallab = get_string ();
239       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
240               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
241       if (!match_byte (1) && !match_byte(2))
242         match_byte_assert (3);
243       match_byte (0);
244       match_byte (0);
245       match_byte (0);
246       match_byte (0);
247       match_byte (0);
248       match_byte (0);
249       match_byte (0);
250     }
251   else if (match_byte (4))
252     {
253       unsigned int format;
254       char *var, *vallab, *value;
255
256       match_byte_assert (0x58);
257       format = get_u32 ();
258       vallab = get_string ();
259       var = get_string ();
260       if (!match_byte(1) && !match_byte(2))
261         match_byte_assert (3);
262       value = get_string ();
263       printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
264               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
265       match_byte (0);
266       match_byte (0);
267       match_byte (0);
268       match_byte (0);
269     }
270   else if (match_byte (1))
271     {
272       unsigned int format;
273       double value;
274
275       if (match_byte (0x31))
276         {
277           if (match_u32 (1))
278             {
279               printf("(footnote %d) ", get_u32());
280               match_byte_assert (0);
281               match_byte_assert (0);
282               int subn = get_u32 ();
283               printf ("nested %d bytes", subn);
284               pos += subn;
285             }
286         }
287       else
288         match_byte_assert (0x58);
289       format = get_u32 ();
290       value = get_double ();
291       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
292       match_byte (1);
293       match_byte (0);
294       match_byte (0);
295       match_byte (0);
296       match_byte (1);
297     }
298   else if (match_byte (0x31))
299     {
300       if (match_u32 (1))
301         {
302           printf("(footnote %d) ", get_u32());
303           match_byte_assert (0);
304           match_byte_assert (0);
305           int subn = get_u32 ();
306           printf ("nested %d bytes", subn);
307           pos += subn;
308         }
309       else
310         {
311           match_u32_assert (0);
312           match_u32_assert (0);
313           int subn = get_u32 ();
314           printf ("nested %d bytes", subn);
315           pos += subn;
316         }
317       char *base = get_string();
318       int x = get_u32();
319       printf ("\"%s\"; %d variables:\n", base, x);
320       if (match_u32(0))
321         {
322           for (int i = 0; i < x; i++)
323             {
324               dump_value (level+1);
325               putchar('\n');
326             }
327         }
328       else
329         {
330           for (int i = 0; i < x; i++)
331             {
332               int y = get_u32();
333               match_u32_assert(0);
334               for (int j = 0; j <= level; j++)
335                 printf ("    ");
336               printf("variable %d has %d values:\n", i, y);
337               for (int j = 0; j < y; j++)
338                 {
339                   if (match_byte(3))
340                     {
341                       char *a = get_string();
342                       match_byte_assert(0x58);
343                       char *b = get_string();
344                       char *c = get_string();
345                       for (int k = 0; k <= level + 1; k++)
346                         printf ("    ");
347                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
348                       match_byte(0);
349                       match_byte(0);
350                       match_byte(0);
351                       match_byte(0);
352                       match_byte(0);
353                     }
354                   else
355                     dump_value (level+1);
356                   putchar('\n');
357                 }
358             }
359         }
360     }
361   else
362     {
363
364       match_byte_assert (0x58);
365       char *base = get_string();
366       int x = get_u32();
367       printf ("\"%s\" with %d variables:\n", base, x);
368       if (match_u32(0))
369         {
370           for (int i = 0; i < x; i++)
371             {
372               dump_value (level+1);
373               putchar('\n');
374             }
375         }
376       else
377         {
378           for (int i = 0; i < x; i++)
379             {
380               int y = get_u32();
381               match_u32_assert(0);
382               for (int j = 0; j <= level; j++)
383                 printf ("    ");
384               printf("variable %d has %d values:\n", i, y);
385               for (int j = 0; j < y; j++)
386                 {
387                   if (match_byte(3))
388                     {
389                       char *a = get_string();
390                       match_byte_assert(0x58);
391                       char *b = get_string();
392                       char *c = get_string();
393                       for (int k = 0; k <= level + 1; k++)
394                         printf ("    ");
395                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
396                       match_byte(0);
397                       match_byte(0);
398                       match_byte(0);
399                       match_byte(0);
400                       match_byte(0);
401                     }
402                   else
403                     dump_value (level+1);
404                   putchar('\n');
405                 }
406             }
407         }
408     }
409 }
410
411 static void
412 dump_dim_value(int level)
413 {
414   for (int i = 0; i <= level; i++)
415     printf ("    ");
416
417   if (match_byte (3))
418     {
419       get_string();
420       if (match_byte (0x31))
421         {
422           match_u32 (1);
423           printf("(footnote %d) ", get_u32());
424           match_byte_assert (0);
425           match_byte_assert (0);
426           int subn = get_u32 ();
427           printf ("nested %d bytes", subn);
428           pos += subn;
429         }
430       else
431         match_byte_assert (0x58);
432       get_string();
433       printf("string \"%s\"", get_string());
434       match_byte (0);
435       match_byte_assert (1);
436       match_byte (0);
437       match_byte (0);
438       match_byte (0);
439       match_byte (1);
440     }
441   else if (match_byte (5))
442     {
443       match_byte_assert (0x58);
444       printf ("variable \"%s\"", get_string());
445       get_string();
446       match_byte_assert (2);
447     }
448   else if (match_byte (2))
449     {
450       unsigned int format;
451       char *var, *vallab;
452       double value;
453
454       match_byte_assert (0x58);
455       format = get_u32 ();
456       value = get_double ();
457       var = get_string ();
458       vallab = get_string ();
459       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
460               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
461       if (!match_u32 (3))
462         match_u32_assert (2);
463       match_byte (0);
464     }
465   else if (match_byte (1))
466     {
467       unsigned int format;
468       double value;
469
470       match_byte_assert (0x58);
471       format = get_u32 ();
472       value = get_double ();
473       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
474       match_byte (1);
475       match_byte (0);
476       match_byte (0);
477       match_byte (0);
478       match_byte (1);
479     }
480   else
481     {
482       int subn;
483
484       match_byte (0);
485       match_byte_assert (0x31);
486       match_u32_assert (0);
487       match_u32_assert (0);
488       subn = get_u32 ();
489       printf ("nested %d bytes", subn);
490       pos += subn;
491       printf ("; \"%s\", substitutions:", get_string());
492       int total_subs = get_u32();
493       int x = get_u32();
494       if (x)
495         {
496           total_subs = (total_subs - 1) + x;
497           match_u32_assert (0);
498         }
499       printf (" (total %d)", total_subs);
500
501       for (int i = 0; i < total_subs; i++)
502         {
503           putc ('\n', stdout);
504           dump_value (level + 1);
505         }
506     }
507 }
508
509 static void
510 dump_category(int level)
511 {
512   match_byte (0);
513   match_byte (0);
514   match_byte (0);
515   match_byte (0);
516   dump_value (level);
517
518   if (match_u32 (2))
519     get_u32 ();
520   else if (match_u32 (1))
521     {
522       match_byte (0);
523       match_byte (0);
524       match_byte (0);
525       get_u32 ();
526     }
527   else if (match_byte (1))
528     {
529       match_byte (0);
530       if (!match_u32 (2))
531         match_u32_assert (1);
532       match_byte (0);
533       get_u32();
534     }
535   else
536     {
537       match_u32_assert (0);
538       get_u32 ();
539     }
540
541   int n_categories = get_u32();
542   if (n_categories > 0)
543     printf (", %d subcategories:", n_categories);
544   printf("\n");
545   for (int i = 0; i < n_categories; i++)
546     dump_category (level + 1);
547 }
548
549 static void
550 dump_dim(void)
551 {
552   int n_categories;
553   printf("next dim\n");
554   match_byte(0);
555   if (match_byte(3))
556     {
557       get_string();
558       match_byte_assert(0x58);
559       get_string();
560       printf("string \"%s\": ", get_string());
561       match_byte(1) || match_byte(0);
562     }
563   else if (match_byte(5)) 
564     {
565       match_byte_assert(0x58);
566       printf("variable \"%s\": ", get_string());
567       get_string();
568       if (!match_byte(2))
569         match_byte_assert(3);
570     }
571   else if (match_byte(0x31))
572     {
573       int subn;
574       int total_subs = 1;
575
576       match_u32_assert (0);
577       match_u32_assert (0);
578       subn = get_u32 ();
579       printf ("nested %d bytes", subn);
580       pos += subn;
581       printf ("; \"%s\", substitutions:", get_string());
582       for (;;)
583         {
584           int n_subst = get_u32();
585           if (!n_subst)
586             break;
587           printf (" %d", n_subst);
588           total_subs *= n_subst;
589         }
590
591       for (int i = 0; i < total_subs; i++)
592         {
593           putc ('\n', stdout);
594           dump_dim_value (0);
595         }
596     }
597   else
598     {
599       int total_subs = 1;
600
601       match_byte_assert (0x58);
602       printf ("\"%s\" with substitutions:", get_string());
603       for (;;)
604         {
605           int n_subst = get_u32();
606           if (!n_subst)
607             break;
608           printf (" %d", n_subst);
609           total_subs *= n_subst;
610         }
611
612       for (int i = 0; i < total_subs; i++)
613         {
614           putc ('\n', stdout);
615           dump_dim_value (0);
616         }
617     }
618
619   /* This byte is usually 0x02 but 0x00 and 0x75 (!) have also been spotted. */
620   pos++;
621
622   if (!match_byte(0) && !match_byte(1))
623     match_byte_assert(2);
624   if (!match_u32(0))
625     match_u32_assert(2);
626   if (!match_byte(0))
627     match_byte_assert(1);
628   match_byte(0);
629   match_byte(0);
630   match_byte(0);
631   match_byte(0);
632   get_u32();
633   match_byte(0);
634   match_byte(0);
635   match_byte(0);
636   match_byte(0);
637   n_categories = get_u32();
638   printf("%d nested categories\n", n_categories);
639   for (int i = 0; i < n_categories; i++)
640     dump_category (0);
641 }
642
643 int n_dims;
644 static void
645 dump_dims(void)
646 {
647   n_dims = get_u32();
648   printf ("%u dimensions\n", n_dims);
649   for (int i = 0; i < n_dims; i++)
650     {
651       printf("\n");
652       dump_dim ();
653     }
654 }
655
656 static void
657 dump_data(void)
658 {
659 #if 1
660   int a[16];
661   for (int i = 0; i < 3 + n_dims; i++)
662     a[i] = get_u32();
663   printf ("data intro:");
664   for (int i = 0; i < 3 + n_dims; i++)
665     printf(" %d", a[i]);
666   printf("\n");
667 #else
668   fprintf (stderr,"data intro (%d dims):", n_dims);
669   for (int i = 0; i < 3+n_dims; i++)
670     fprintf (stderr," %d", get_u32());
671   fprintf(stderr,"\n");
672 #endif
673   int x = get_u32();
674   printf ("%d data values, starting at %08x\n", x, pos);
675   for (int i = 0; i < x; i++)
676     {
677       printf("%08x, index %d:\n", pos, get_u32());
678       match_u32_assert(0);
679       match_byte(0);
680       match_byte(0);
681       match_byte(0);
682       match_byte(0);
683       if (match_byte (1))
684         {
685           unsigned int format;
686           double value;
687
688           if (match_byte (0x31))
689             {
690               if (match_u32 (0))
691                 {
692                   if (match_u32 (1))
693                     get_string();
694                   else
695                     match_u32_assert (0);
696                   int subn = get_u32 ();
697                   printf ("nested %d bytes", subn);
698                   pos += subn;
699                 }
700               else if (match_u32 (1))
701                 {
702                   printf("(footnote %d) ", get_u32());
703                   match_byte_assert (0);
704                   match_byte_assert (0);
705                   int subn = get_u32 ();
706                   printf ("nested %d bytes", subn);
707                   pos += subn;
708                 }
709               else
710                 {
711                   match_u32_assert(2);
712                   printf("(special 2)");
713                   match_byte_assert(0);
714                   match_byte_assert(0);
715                   match_u32_assert(1);
716                   match_byte_assert(0);
717                   match_byte_assert(0);
718                   int subn = get_u32 ();
719                   printf ("nested %d bytes", subn);
720                   pos += subn;
721                 }
722             }
723           else
724             match_byte_assert (0x58);
725           format = get_u32 ();
726           value = get_double ();
727           printf ("    value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
728         }
729       else if (match_byte (3))
730         {
731           get_string();
732           if (match_byte (0x31))
733             {
734               if (match_u32 (0))
735                 {
736                   match_u32_assert (1);
737                   get_string ();
738                   int subn = get_u32 ();
739                   printf ("nested %d bytes", subn);
740                   pos += subn;
741                 }
742               else if (match_u32 (1))
743                 {
744                   printf("(footnote %d) ", get_u32());
745                   match_byte_assert (0);
746                   match_byte_assert (0);
747                   int subn = get_u32 ();
748                   printf ("nested %d bytes", subn);
749                   pos += subn;
750                 }
751               else if (match_u32 (2))
752                 {
753                   printf("(special 2)");
754                   match_byte_assert(0);
755                   match_byte_assert(0);
756                   match_u32_assert(1);
757                   match_byte_assert(0);
758                   match_byte_assert(0);
759                   int subn = get_u32 ();
760                   printf ("nested %d bytes", subn);
761                   pos += subn;
762                 }
763               else
764                 {
765                   match_u32_assert(3);
766                   printf("(special 3)");
767                   match_byte_assert(0);
768                   match_byte_assert(0);
769                   match_byte_assert(1);
770                   match_byte_assert(0);
771                   int subn = get_u32 ();
772                   printf ("nested %d bytes, ", subn);
773                   pos += subn;
774                   subn = get_u32 ();
775                   printf ("nested %d bytes, ", subn);
776                   pos += subn;
777                 }
778             }
779           else
780             match_byte_assert (0x58);
781           get_string();
782           printf("string \"%s\"", get_string());
783           match_byte (0);
784         }
785       else if (match_byte (2))
786         {
787           unsigned int format;
788           char *var, *vallab;
789           double value;
790
791           match_byte_assert (0x58);
792           format = get_u32 ();
793           value = get_double ();
794           var = get_string ();
795           vallab = get_string ();
796           printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
797                   value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
798           if (!match_byte (1) && !match_byte(2))
799             match_byte_assert (3);
800         }
801       else if (match_byte (4))
802         {
803           unsigned int format;
804           char *var, *vallab, *value;
805
806           match_byte_assert (0x58);
807           format = get_u32 ();
808           vallab = get_string ();
809           var = get_string ();
810           if (!match_byte(1) && !match_byte(2))
811             match_byte_assert (3);
812           value = get_string ();
813           printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
814                   value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
815         }
816       else if (match_byte (5))
817         {
818           match_byte_assert (0x58);
819           printf ("variable \"%s\"", get_string());
820           get_string();
821           if (!match_byte(1) && !match_byte(2))
822             match_byte_assert(3);
823           match_byte (0);
824           match_byte (0);
825           match_byte (0);
826           match_byte (0);
827         }
828       else if (match_byte(0x31))
829         {
830           if (match_u32 (1))
831             {
832               printf("(footnote %d) ", get_u32());
833               match_byte_assert (0);
834               match_byte_assert (0);
835               int subn = get_u32 ();
836               printf ("nested %d bytes", subn);
837               pos += subn;
838             }
839           else
840             {
841               match_u32_assert (0);
842               match_u32_assert (0);
843               int subn = get_u32 ();
844               printf ("nested %d bytes", subn);
845               pos += subn;
846             }
847           char *base = get_string();
848           int x = get_u32();
849           printf ("\"%s\"; %d variables:\n", base, x);
850           for (int i = 0; i < x; i++)
851             {
852               int y = get_u32();
853               if (!y)
854                 y = 1;
855               else
856                 match_u32_assert(0);
857               for (int j = 0; j <= 0; j++)
858                 printf ("    ");
859               printf("variable %d has %d values:\n", i, y);
860               for (int j = 0; j < y; j++)
861                 {
862                   if (match_byte (1))
863                     {
864                       unsigned int format;
865                       double value;
866
867                       if (match_byte (0x31))
868                         {
869                           if (match_u32 (0))
870                             {
871                               if (match_u32 (1))
872                                 get_string();
873                               else
874                                 match_u32_assert (0);
875                               int subn = get_u32 ();
876                               printf ("nested %d bytes", subn);
877                               pos += subn;
878                             }
879                           else if (match_u32 (1))
880                             {
881                               printf("(footnote %d) ", get_u32());
882                               match_byte_assert (0);
883                               match_byte_assert (0);
884                               int subn = get_u32 ();
885                               printf ("nested %d bytes", subn);
886                               pos += subn;
887                             }
888                           else
889                             {
890                               match_u32_assert(2);
891                               printf("(special 2)");
892                               match_byte_assert(0);
893                               match_byte_assert(0);
894                               match_u32_assert(1);
895                               match_byte_assert(0);
896                               match_byte_assert(0);
897                               int subn = get_u32 ();
898                               printf ("nested %d bytes", subn);
899                               pos += subn;
900                             }
901                         }
902                       else
903                         match_byte_assert (0x58);
904                       format = get_u32 ();
905                       value = get_double ();
906                       printf ("    value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
907                     }
908                   else if (match_byte(3))
909                     {
910                       char *a = get_string();
911                       match_byte_assert(0x58);
912                       char *b = get_string();
913                       char *c = get_string();
914                       for (int k = 0; k <= 1; k++)
915                         printf ("    ");
916                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
917                       match_byte(0);
918                       match_byte(0);
919                       match_byte(0);
920                       match_byte(0);
921                     }
922                   else if (match_byte(5))
923                     {
924                       match_byte_assert (0x58);
925                       printf ("variable \"%s\"", get_string());
926                       get_string();
927                       if (!match_byte(1) && !match_byte(2))
928                         match_byte_assert(3);
929                       match_byte (0);
930                       match_byte (0);
931                       match_byte (0);
932                       match_byte (0);
933                     }
934                   else
935                     dump_value (0);
936                   putchar('\n');
937                 }
938             }
939         }
940       else
941         {
942           match_byte_assert (0x58);
943           char *base = get_string();
944           int x = get_u32();
945           printf ("\"%s\" with %d variables:\n", base, x);
946           if (match_u32(0))
947             {
948               for (int i = 0; i < x; i++)
949                 {
950                   if (match_byte(3))
951                     {
952                       char *a = get_string();
953                       match_byte_assert(0x58);
954                       char *b = get_string();
955                       char *c = get_string();
956                       for (int k = 0; k <= 1; k++)
957                         printf ("    ");
958                       printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
959                       match_byte(0);
960                       match_byte(0);
961                       match_byte(0);
962                       match_byte(0);
963                       match_byte(0);
964                     }
965                   else
966                     dump_value (1);
967                   putchar('\n');
968                 }
969             }
970           else
971             {
972               for (int i = 0; i < x; i++)
973                 {
974                   int y = get_u32();
975                   match_u32_assert(0);
976                   for (int j = 0; j <= 0; j++)
977                     printf ("    ");
978                   printf("variable %d has %d values:\n", i, y);
979                   for (int j = 0; j < y; j++)
980                     {
981                       if (match_byte(3))
982                         {
983                           char *a = get_string();
984                           match_byte_assert(0x58);
985                           char *b = get_string();
986                           char *c = get_string();
987                           for (int k = 0; k <= 1; k++)
988                             printf ("    ");
989                           printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
990                           match_byte(0);
991                           match_byte(0);
992                           match_byte(0);
993                           match_byte(0);
994                           match_byte(0);
995                         }
996                       else
997                         dump_value (1);
998                       putchar('\n');
999                     }
1000                 }
1001             }
1002         }
1003       putchar('\n');
1004     }
1005 }
1006
1007 int
1008 main(int argc, char *argv[])
1009 {
1010   size_t start;
1011   struct stat s;
1012
1013   if (isatty(STDIN_FILENO))
1014     {
1015       fprintf(stderr, "redirect stdin from a .bin file\n");
1016       exit(1);
1017     }
1018   if (fstat(STDIN_FILENO, &s))
1019     {
1020       perror("fstat");
1021       exit(1);
1022     }
1023   n = s.st_size;
1024   data = malloc(n);
1025   if (!data)
1026     {
1027       perror("malloc");
1028       exit(1);
1029     }
1030   if (read(STDIN_FILENO, data, n) != n)
1031     {
1032       perror("read");
1033       exit(1);
1034     }
1035
1036   if (argc > 1)
1037     {
1038       if (!strcmp(argv[1], "title0"))
1039         {
1040           pos = 0x27;
1041           if (match_byte (0x03)
1042               || (match_byte (0x05) && match_byte (0x58)))
1043             printf ("%s\n", get_string());
1044           else
1045             printf ("<unknown>\n");
1046           return 0;
1047         }
1048       if (!strcmp(argv[1], "title"))
1049         {
1050           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1051           start = 0x27;
1052           n = find(fonts, sizeof fonts - 1);
1053         }
1054       else if (!strcmp(argv[1], "fonts"))
1055         {
1056           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1057           const char styles[] = "\xf0\0\0\0";
1058           start = find(fonts, sizeof fonts - 1);
1059           n = find(styles, sizeof styles - 1);
1060         }
1061       else if (!strcmp(argv[1], "styles"))
1062         {
1063           const char styles[] = "\xf0\0\0\0";
1064           const char dimensions[] = "-,,,.\0";
1065           start = find(styles, sizeof styles - 1);
1066           n = find(dimensions, sizeof dimensions - 1) + sizeof dimensions - 1;
1067         }
1068       else if (!strcmp(argv[1], "dimensions"))
1069         {
1070           {
1071             const char dimensions[] = "-,,,.\0";
1072             start = try_find_tail(dimensions, sizeof dimensions - 1);
1073           }
1074
1075           if (!start)
1076             {
1077               const char dimensions[] = "-,,, .\0";
1078               start = find_tail(dimensions, sizeof dimensions - 1);
1079             }
1080
1081           pos = start;
1082           dump_dims ();
1083           dump_data ();
1084           start = pos;
1085         }
1086       else
1087         {
1088           fprintf (stderr, "unknown section %s\n", argv[1]);
1089           exit(1);
1090         }
1091     }
1092   else
1093     start = 0x27;
1094
1095   for (size_t i = start; i < n; )
1096     {
1097       if (i + 5 <= n
1098           && data[i]
1099           //&& !data[i + 1]
1100           && !data[i + 2]
1101           && !data[i + 3]
1102           && i + 4 + data[i] + data[i + 1] * 256 <= n
1103           && all_ascii(&data[i + 4], data[i] + data[i + 1] * 256))
1104         {
1105           fputs("\n\"", stdout);
1106           fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stdout);
1107           fputs("\" ", stdout);
1108
1109           i += 4 + data[i] + data[i + 1] * 256;
1110         }
1111       else if (i + 12 <= n
1112                && data[i + 1] == 40
1113                && data[i + 2] == 5
1114                && data[i + 3] == 0)
1115         {
1116           double d;
1117
1118           memcpy (&d, &data[i + 4], 8);
1119           printf ("F40.%d(%.*f)\n", data[i], data[i], d);
1120           i += 12;
1121         }
1122       else if (i + 12 <= n
1123                && data[i + 1] == 40
1124                && data[i + 2] == 31
1125                && data[i + 3] == 0)
1126         {
1127           double d;
1128
1129           memcpy (&d, &data[i + 4], 8);
1130           printf ("PCT40.%d(%.*f)\n", data[i], data[i], d);
1131           i += 12;
1132         }
1133       else if (i + 4 <= n
1134                && (data[i] && data[i] != 88 && data[i] != 0x41)
1135                && !data[i + 1]
1136                && !data[i + 2]
1137                && !data[i + 3])
1138         {
1139           printf ("i%d ", data[i]);
1140           i += 4;
1141         }
1142       else
1143         {
1144           printf("%02x ", data[i]);
1145           i++;
1146         }
1147     }
1148
1149   return 0;
1150 }