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