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