Write dump_title_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     }
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 (data[pos] == 5)
504     dump_value (0);
505   else
506     {
507       dump_value_31();
508       char *base = get_string();
509       int x = get_u32();
510       printf ("\"%s\"; %d variables:\n", base, x);
511       for (int i = 0; i < x; i++)
512         {
513           int y = get_u32();
514           if (!y)
515             y = 1;
516           else
517             match_u32_assert(0);
518           for (int j = 0; j <= 0; j++)
519             printf ("    ");
520           printf("variable %d has %d values:\n", i, y);
521           for (int j = 0; j < y; j++)
522             dump_data_value();
523         }
524     }
525 }
526
527 static void
528 dump_data(void)
529 {
530 #if 1
531   int a[16];
532   for (int i = 0; i < 3 + n_dims; i++)
533     a[i] = get_u32();
534   printf ("data intro:");
535   for (int i = 0; i < 3 + n_dims; i++)
536     printf(" %d", a[i]);
537   printf("\n");
538 #else
539   fprintf (stderr,"data intro (%d dims):", n_dims);
540   for (int i = 0; i < 3+n_dims; i++)
541     fprintf (stderr," %d", get_u32());
542   fprintf(stderr,"\n");
543 #endif
544   int x = get_u32();
545   printf ("%d data values, starting at %08x\n", x, pos);
546   for (int i = 0; i < x; i++)
547     {
548       printf("%08x, index %d:\n", pos, get_u32());
549       match_u32_assert(0);
550       dump_data_value();
551       putchar('\n');
552     }
553 }
554
555 static void
556 dump_title_value(int level)
557 {
558   for (int i = 0; i <= level; i++)
559     printf ("    ");
560
561   match_byte (0);
562   match_byte (0);
563   match_byte (0);
564   match_byte (0);
565   if (data[pos] == 3 || data[pos] == 2 || data[pos] == 4 || data[pos] == 1)
566     dump_value(level);
567   else if (match_byte (5))
568     {
569       dump_value_31();
570       printf ("variable \"%s\"", get_string());
571       get_string();
572       if (!match_byte(1) && !match_byte(2))
573         match_byte_assert(3);
574     }
575   else
576     {
577       dump_value_31();
578
579       char *base = get_string();
580       int x = get_u32();
581       printf ("\"%s\" with %d variables:\n", base, x);
582       for (int i = 0; i < x; i++)
583         {
584           int y = get_u32();
585           if (!y)
586             y = 1;
587           else
588             match_u32_assert(0);
589           for (int j = 0; j <= level; j++)
590             printf ("    ");
591           printf("variable %d has %d values:\n", i, y);
592           for (int j = 0; j < y; j++)
593             {
594               match_byte(0);
595               if (match_byte(3))
596                 {
597                   char *a = get_string();
598                   match_byte_assert(0x58);
599                   char *b = get_string();
600                   char *c = get_string();
601                   for (int k = 0; k <= level + 1; k++)
602                     printf ("    ");
603                   printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
604                 }
605               else
606                 dump_title_value (level+1);
607               putchar('\n');
608             }
609         }
610     }
611 }
612
613 static void
614 dump_footnote_value(int level)
615 {
616   for (int i = 0; i <= level; i++)
617     printf ("    ");
618
619   match_byte (0);
620   match_byte (0);
621   match_byte (0);
622   match_byte (0);
623   if (match_byte (3))
624     {
625       get_string();
626       dump_value_31();
627       get_string();
628       printf("string \"%s\"", get_string());
629       if (!match_byte (0))
630         match_byte_assert (1);
631     }
632   else if (match_byte (5))
633     {
634       match_byte_assert (0x58);
635       printf ("variable \"%s\"", get_string());
636       get_string();
637       if (!match_byte(1) && !match_byte(2))
638         match_byte_assert(3);
639     }
640   else if (match_byte (2))
641     {
642       unsigned int format;
643       char *var, *vallab;
644       double value;
645
646       match_byte_assert (0x58);
647       format = get_u32 ();
648       value = get_double ();
649       var = get_string ();
650       vallab = get_string ();
651       printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
652               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
653       if (!match_byte (1) && !match_byte(2))
654         match_byte_assert (3);
655       match_byte (0);
656       match_byte (0);
657       match_byte (0);
658     }
659   else if (match_byte (4))
660     {
661       unsigned int format;
662       char *var, *vallab, *value;
663
664       match_byte_assert (0x58);
665       format = get_u32 ();
666       vallab = get_string ();
667       var = get_string ();
668       if (!match_byte(1) && !match_byte(2))
669         match_byte_assert (3);
670       value = get_string ();
671       printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
672               value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
673       match_byte (0);
674       match_byte (0);
675       match_byte (0);
676     }
677   else if (match_byte (1))
678     {
679       unsigned int format;
680       double value;
681
682       dump_value_31();
683       format = get_u32 ();
684       value = get_double ();
685       printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
686     }
687   else
688     {
689       dump_value_31();
690       char *base = get_string();
691       int x = get_u32();
692       printf ("\"%s\"; %d variables:\n", base, x);
693       for (int i = 0; i < x; i++)
694         {
695           int y = get_u32();
696           if (!y)
697             y = 1;
698           else
699             match_u32_assert(0);
700           for (int j = 0; j <= level; j++)
701             printf ("    ");
702           printf("variable %d has %d values:\n", i, y);
703           for (int j = 0; j < y; j++)
704             {
705               dump_footnote_value (level+1);
706               putchar('\n');
707             }
708         }
709     }
710 }
711
712 static void
713 dump_title(void)
714 {
715   pos = 0x27;
716   dump_title_value(0); putchar('\n');
717   dump_title_value(0); putchar('\n');
718   match_byte_assert(0x31);
719   dump_title_value(0); putchar('\n');
720   match_byte(0);
721   match_byte_assert(0x58);
722   if (match_byte(0x31))
723     {
724       dump_footnote_value(0); putchar('\n');
725     }
726   else
727     match_byte_assert(0x58);
728
729
730   int n_footnotes = get_u32();
731   if (n_footnotes >= 20)
732     {
733       fprintf(stderr, "%08x: %d footnotes\n", pos - 4, n_footnotes);
734       exit(1);
735     }
736
737   printf("------\n%d footnotes\n", n_footnotes);
738   if (n_footnotes < 20)
739     {
740       for (int i = 0; i < n_footnotes; i++)
741         {
742           printf("footnote %d:\n", i);
743           dump_footnote_value(0);
744           match_byte(0);
745           match_byte(0);
746           match_byte(0);
747           match_byte(0);
748           if (match_byte (0x31))
749             {
750               /* Custom footnote marker string. */
751               match_byte_assert(3);
752               get_string();
753               match_byte_assert(0x58);
754               match_u32_assert(0);
755               get_string();
756             }
757           else
758             match_byte_assert (0x58);
759           printf("(%d)\n", get_u32());
760         }
761     }
762 }
763
764 static int
765 find_dimensions(void)
766 {
767   {
768     const char dimensions[] = "-,,,.\0";
769     int x = try_find_tail(dimensions, sizeof dimensions - 1);
770     if (x)
771       return x;
772   }
773
774   const char dimensions[] = "-,,, .\0";
775   return find_tail(dimensions, sizeof dimensions - 1);
776 }
777
778 static void
779 dump_fonts(void)
780 {
781   printf("fonts: offset=%08x\n", pos);
782   match_byte(0);
783   for (int i = 1; i <= 8; i++)
784     {
785       printf("%08x: font %d, ", pos, i);
786       match_byte_assert(i);
787       match_byte_assert(0x31);
788       printf("%s, ", get_string());
789       match_byte_assert(0);
790       match_byte_assert(0);
791       if (!match_byte(0x40) && !match_byte(0x20) && !match_byte(0x80) && !match_byte(0x10))
792         match_byte_assert(0x50);
793       if (!match_byte(0x41))
794         match_byte_assert(0x51);
795       pos += 13;
796       printf ("%s, ", get_string());
797       printf ("%s, ", get_string());
798       match_u32_assert(0);
799       match_u32_assert(0);
800       pos++;
801       get_u32();
802       get_u32();
803       get_u32();
804       get_u32();
805       putchar('\n');
806     }
807
808   match_u32_assert(240);
809   pos += 240;
810
811   match_u32_assert(18);
812   pos += 18;
813
814   if (match_u32(117))
815     pos += 117;
816   else
817     {
818       match_u32_assert(142);
819       pos += 142;
820     }
821
822   int count = get_u32();
823   pos += 4 * count;
824
825   char *encoding = get_string();
826   printf("encoding=%s\n", encoding);
827
828   if (!match_u32(0))
829     match_u32_assert(UINT32_MAX);
830   if (!match_byte(0))
831     match_byte_assert(1);
832   match_byte_assert(0);
833   if (!match_byte(0))
834     match_byte_assert(1);
835   if (!match_byte(0x99) && !match_byte(0x98))
836     match_byte_assert(0x97);
837   match_byte_assert(7);
838   match_byte_assert(0);
839   match_byte_assert(0);
840   if (match_byte('.'))
841     match_byte_assert(',');
842   else
843     {
844       match_byte_assert(',');
845       if (!match_byte('.'))
846         match_byte_assert(' ');
847     }
848   match_u32_assert(5);
849   for (int i = 0; i < 5; i++)
850     get_string();
851   pos += get_u32();
852   if (pos != find_dimensions())
853     fprintf (stderr, "%08x / %08x\n", pos, find_dimensions());
854 }
855
856 int
857 main(int argc, char *argv[])
858 {
859   size_t start;
860   struct stat s;
861
862   if (isatty(STDIN_FILENO))
863     {
864       fprintf(stderr, "redirect stdin from a .bin file\n");
865       exit(1);
866     }
867   if (fstat(STDIN_FILENO, &s))
868     {
869       perror("fstat");
870       exit(1);
871     }
872   n = s.st_size;
873   data = malloc(n);
874   if (!data)
875     {
876       perror("malloc");
877       exit(1);
878     }
879   if (read(STDIN_FILENO, data, n) != n)
880     {
881       perror("read");
882       exit(1);
883     }
884
885   if (argc > 1)
886     {
887       if (!strcmp(argv[1], "title0"))
888         {
889           pos = 0x27;
890           if (match_byte (0x03)
891               || (match_byte (0x05) && match_byte (0x58)))
892             printf ("%s\n", get_string());
893           else
894             printf ("<unknown>\n");
895           return 0;
896         }
897       else if (!strcmp(argv[1], "title"))
898         {
899           dump_title();
900           exit(0);
901         }
902       else if (!strcmp(argv[1], "titleraw"))
903         {
904           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
905           start = 0x27;
906           n = find(fonts, sizeof fonts - 1);
907         }
908       else if (!strcmp(argv[1], "fonts"))
909         {
910           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
911           const char styles[] = "\xf0\0\0\0";
912           start = find(fonts, sizeof fonts - 1);
913           n = find(styles, sizeof styles - 1);
914         }
915       else if (!strcmp(argv[1], "styles"))
916         {
917           const char styles[] = "\xf0\0\0\0";
918           const char dimensions[] = "-,,,.\0";
919           start = find(styles, sizeof styles - 1);
920           n = find(dimensions, sizeof dimensions - 1) + sizeof dimensions - 1;
921         }
922       else if (!strcmp(argv[1], "dimensions") || !strcmp(argv[1], "all"))
923         {
924           pos = 0;
925           match_byte_assert(1);
926           match_byte_assert(0);
927           match_u32_assert(3);
928           match_byte_assert(1);
929           if (!match_byte(0))
930             match_byte_assert(1);
931           match_byte_assert(0);
932           match_byte_assert(0);
933           if (!match_byte(0))
934             match_byte_assert(1);
935           pos++;
936           match_byte_assert(0);
937           match_byte_assert(0);
938           match_byte_assert(0);
939           dump_title ();
940           dump_fonts();
941           dump_dims ();
942           printf("\n\ndata:\n");
943           dump_data ();
944           if (pos == n - 1)
945             match_byte_assert (1);
946           if (pos != n)
947             {
948               fprintf (stderr, "%x / %x\n", pos, n);
949               exit(1);
950             }
951           exit(0);
952         }
953       else
954         {
955           fprintf (stderr, "unknown section %s\n", argv[1]);
956           exit(1);
957         }
958     }
959   else
960     start = 0x27;
961
962   for (size_t i = start; i < n; )
963     {
964       if (i + 5 <= n
965           && data[i]
966           //&& !data[i + 1]
967           && !data[i + 2]
968           && !data[i + 3]
969           && i + 4 + data[i] + data[i + 1] * 256 <= n
970           && all_ascii(&data[i + 4], data[i] + data[i + 1] * 256))
971         {
972           fputs("\n\"", stdout);
973           fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stdout);
974           fputs("\" ", stdout);
975
976           i += 4 + data[i] + data[i + 1] * 256;
977         }
978       else if (i + 12 <= n
979                && data[i + 1] == 40
980                && data[i + 2] == 5
981                && data[i + 3] == 0)
982         {
983           double d;
984
985           memcpy (&d, &data[i + 4], 8);
986           printf ("F40.%d(%.*f)\n", data[i], data[i], d);
987           i += 12;
988         }
989       else if (i + 12 <= n
990                && data[i + 1] == 40
991                && data[i + 2] == 31
992                && data[i + 3] == 0)
993         {
994           double d;
995
996           memcpy (&d, &data[i + 4], 8);
997           printf ("PCT40.%d(%.*f)\n", data[i], data[i], d);
998           i += 12;
999         }
1000       else if (i + 4 <= n
1001                && (data[i] && data[i] != 88 && data[i] != 0x41)
1002                && !data[i + 1]
1003                && !data[i + 2]
1004                && !data[i + 3])
1005         {
1006           printf ("i%d ", data[i]);
1007           i += 4;
1008         }
1009       else
1010         {
1011           printf("%02x ", data[i]);
1012           i++;
1013         }
1014     }
1015
1016   return 0;
1017 }