a7ccbdc88b1cbb1facd1b19015a1fdfdbf13f229
[pspp] / dump.c
1 #include <float.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9
10 static uint8_t *data;
11 static size_t n;
12
13 static bool
14 all_ascii(const uint8_t *p, size_t n)
15 {
16   for (size_t i = 0; i < n; i++)
17     if (p[i] < 32 || p[i] > 126)
18       return false;
19   return true;
20 }
21
22 static size_t
23 try_find(const char *target, size_t target_len)
24 {
25   const uint8_t *pos = (const uint8_t *) memmem (data, n, target, target_len);
26   return pos ? pos - data : 0;
27 }
28
29 static size_t
30 find(const char *target, size_t target_len)
31 {
32   size_t pos = try_find(target, target_len);
33   if (!pos)
34     {
35       fprintf (stderr, "not found\n");
36       exit(1);
37     }
38   return pos;
39 }
40
41 size_t pos;
42
43 #define XSTR(x) #x
44 #define STR(x) XSTR(x)
45 #define WHERE __FILE__":" STR(__LINE__)
46
47 static unsigned int
48 get_u32(void)
49 {
50   uint32_t x;
51   memcpy(&x, &data[pos], 4);
52   pos += 4;
53   return x;
54 }
55
56 static double
57 get_double(void)
58 {
59   double x;
60   memcpy(&x, &data[pos], 8);
61   pos += 8;
62   return x;
63 }
64
65 static bool
66 match_u32(uint32_t x)
67 {
68   if (get_u32() == x)
69     return true;
70   pos -= 4;
71   return false;
72 }
73
74 static void
75 match_u32_assert(uint32_t x, const char *where)
76 {
77   unsigned int y = get_u32();
78   if (x != y)
79     {
80       fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
81       exit(1);
82     }
83 }
84 #define match_u32_assert(x) match_u32_assert(x, WHERE)
85
86 static bool
87 match_byte(uint8_t b)
88 {
89   if (pos < n && data[pos] == b)
90     {
91       pos++;
92       return true;
93     }
94   else
95     return false;
96 }
97
98 static void
99 match_byte_assert(uint8_t b, const char *where)
100 {
101   if (!match_byte(b))
102     {
103       fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
104       exit(1);
105     }
106 }
107 #define match_byte_assert(b) match_byte_assert(b, WHERE)
108
109 static void
110 newline(FILE *stream, int pos)
111 {
112   fprintf(stream, "\n%08x: ", pos);
113 }
114
115 static void
116 dump_raw(FILE *stream, int start, int end)
117 {
118   for (size_t i = start; i < end; )
119     {
120       if (i + 5 <= n
121           && data[i]
122           //&& !data[i + 1]
123           && !data[i + 2]
124           && !data[i + 3]
125           && i + 4 + data[i] + data[i + 1] * 256 <= end
126           && all_ascii(&data[i + 4], data[i] + data[i + 1] * 256))
127         {
128           newline(stream, i);
129           fprintf(stream, "\"");
130           fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stream);
131           fputs("\" ", stream);
132
133           i += 4 + data[i] + data[i + 1] * 256;
134         }
135       else if (i + 12 <= end
136                && data[i + 1] == 40
137                && data[i + 2] == 5
138                && data[i + 3] == 0)
139         {
140           double d;
141
142           memcpy (&d, &data[i + 4], 8);
143           fprintf (stream, "F40.%d(%.*f)", data[i], data[i], d);
144           i += 12;
145           newline (stream, i);
146         }
147       else if (i + 12 <= end
148                && data[i + 1] == 40
149                && data[i + 2] == 31
150                && data[i + 3] == 0)
151         {
152           double d;
153
154           memcpy (&d, &data[i + 4], 8);
155           fprintf (stream, "PCT40.%d(%.*f)", data[i], data[i], d);
156           i += 12;
157           newline(stream, i);
158         }
159       else if (i + 4 <= end
160                && (data[i] && data[i] != 88 && data[i] != 0x41)
161                && !data[i + 1]
162                && !data[i + 2]
163                && !data[i + 3])
164         {
165           fprintf (stream, "i%d ", data[i]);
166           i += 4;
167         }
168       else
169         {
170           fprintf(stream, "%02x ", data[i]);
171           i++;
172         }
173     }
174
175
176 }
177
178 static char *
179 get_string(const char *where)
180 {
181   if (1
182       /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
183       /*&& all_ascii(&data[pos + 4], data[pos])*/)
184     {
185       int len = data[pos] + data[pos + 1] * 256;
186       char *s = malloc(len + 1);
187
188       memcpy(s, &data[pos + 4], len);
189       s[len] = 0;
190       pos += 4 + len;
191       return s;
192     }
193   else
194     {
195       fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
196       exit(1);
197     }
198 }
199 #define get_string() get_string(WHERE)
200
201 static char *
202 dump_nested_string(void)
203 {
204   char *s = NULL;
205
206   match_byte_assert (0);
207   match_byte_assert (0);
208   int outer_end = pos + get_u32();
209   int inner_end = pos + get_u32();
210   if (pos != inner_end)
211     {
212       match_u32_assert(0);
213       if (match_byte(0x31))
214         s = get_string();
215       else
216         match_byte_assert(0x58);
217       if (pos != inner_end)
218         {
219           fprintf(stderr, "inner end discrepancy\n");
220           exit(1);
221         }
222     }
223   match_byte_assert(0x58);
224   match_byte_assert(0x58);
225   if (pos != outer_end)
226     {
227       fprintf(stderr, "outer end discrepancy\n");
228       exit(1);
229     }
230
231   return s;
232 }
233
234 static void
235 dump_value_31(FILE *stream)
236 {
237   if (match_byte (0x31))
238     {
239       if (match_u32 (0))
240         {
241           if (match_u32 (1))
242             {
243               /* Only "a" observed as a sample value (although it appears 44 times in the corpus). */
244               get_string();
245             }
246           else
247             match_u32_assert (0);
248
249           int outer_end = pos + get_u32();
250           int inner_end = pos + get_u32();
251           match_u32_assert(0);
252           if (match_byte(0x31))
253             {
254               /* Appears to be a template string, e.g. '^1 cells (^2) expf < 5. Min exp = ^3...'.
255                  Probably doesn't actually appear in output because many examples look unpolished,
256                  e.g. 'partial list cases value ^1 shown upper...' */
257               get_string();
258             }
259           else
260             match_byte_assert(0x58);
261           if (pos != inner_end)
262             {
263               fprintf(stderr, "inner end discrepancy\n");
264               exit(1);
265             }
266
267           if (match_byte(0x31))
268             {
269               /* Only one example in the corpus. */
270               match_byte(1);
271               match_byte(0);
272               match_byte(0);
273               match_byte(0);
274               match_byte_assert(1);
275               get_string();     /* foreground */
276               get_string();     /* background */
277               get_string();     /* font */
278               if (!match_byte(14))
279                 match_byte_assert(12); /* size? */
280             }
281           else
282             match_byte_assert(0x58);
283           match_byte_assert(0x58);
284           if (pos != outer_end)
285             {
286               fprintf(stderr, "outer end discrepancy\n");
287               exit(1);
288             }
289         }
290       else if (match_u32 (1))
291         {
292           fprintf(stream, "(footnote %d) ", get_u32());
293           dump_nested_string();
294         }
295       else if (match_u32 (2))
296         {
297           fprintf(stream, "(special 2)");
298           match_byte_assert(0);
299           match_byte_assert(0);
300           if (!match_u32 (2))
301             match_u32_assert(1);
302           dump_nested_string(); /* Our corpus doesn't contain any examples with strings though. */
303         }
304       else
305         {
306           match_u32_assert(3);
307           fprintf(stream, "(special 3)");
308           match_byte_assert(0);
309           match_byte_assert(0);
310           match_byte_assert(1);
311           match_byte_assert(0);
312           match_u32_assert(2);
313           dump_nested_string(); /* Our corpus doesn't contain any examples with strings though. */
314         }
315     }
316   else
317     match_byte_assert (0x58);
318 }
319
320 static const char *
321 format_to_string (int type)
322 {
323   static char tmp[16];
324   switch (type)
325     {
326     case 1: return "A";
327     case 2: return "AHEX";
328     case 3: return "COMMA";
329     case 4: return "DOLLAR";
330     case 5: case 40: return "F";
331     case 6: return "IB";
332     case 7: return "PIBHEX";
333     case 8: return "P";
334     case 9: return "PIB";
335     case 10: return "PK";
336     case 11: return "RB";
337     case 12: return "RBHEX";
338     case 15: return "Z";
339     case 16: return "N";
340     case 17: return "E";
341     case 20: return "DATE";
342     case 21: return "TIME";
343     case 22: return "DATETIME";
344     case 23: return "ADATE";
345     case 24: return "JDATE";
346     case 25: return "DTIME";
347     case 26: return "WKDAY";
348     case 27: return "MONTH";
349     case 28: return "MOYR";
350     case 29: return "QYR";
351     case 30: return "WKYR";
352     case 31: return "PCT";
353     case 32: return "DOT";
354     case 33: return "CCA";
355     case 34: return "CCB";
356     case 35: return "CCC";
357     case 36: return "CCD";
358     case 37: return "CCE";
359     case 38: return "EDATE";
360     case 39: return "SDATE";
361     default:
362       abort();
363       sprintf(tmp, "<%d>", type);
364       return tmp;
365     }
366 }
367
368 static void
369 dump_value(FILE *stream, int level, bool match1)
370 {
371   match_byte(0);
372   match_byte(0);
373   match_byte(0);
374   match_byte(0);
375
376   for (int i = 0; i <= level; i++)
377     fprintf (stream, "    ");
378
379   if (match_byte (3))
380     {
381       char *text = get_string();
382       dump_value_31(stream);
383       char *identifier = get_string();
384       char *text_eng = get_string();
385       fprintf (stream, "<string c=\"%s\"", text_eng);
386       if (identifier[0])
387         fprintf (stream, " identifier=\"%s\"", identifier);
388       if (strcmp(text_eng, text))
389         fprintf (stream, " local=\"%s\"", text);
390       fprintf (stream, "/>\n");
391       if (!match_byte (0))
392         match_byte_assert(1);
393       if (match1)
394         match_byte (1);
395     }
396   else if (match_byte (5))
397     {
398       dump_value_31(stream);
399       char *name = get_string ();
400       char *label = get_string ();
401       fprintf (stream, "<variable name=\"%s\"", name);
402       if (label[0])
403         fprintf (stream, " label=\"%s\"", label);
404       fprintf (stream, "/>\n");
405       if (!match_byte(1) && !match_byte(2))
406         match_byte_assert(3);
407     }
408   else if (match_byte (2))
409     {
410       unsigned int format;
411       char *var, *vallab;
412       double value;
413
414       match_byte_assert (0x58);
415       format = get_u32 ();
416       value = get_double ();
417       var = get_string ();
418       vallab = get_string ();
419       fprintf (stream, "<numeric-datum value=\"%.*g\" format=\"%s%d.%d\"",
420               DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
421       if (var[0])
422         fprintf (stream, " variable=\"%s\"", var);
423       if (vallab[0])
424         fprintf (stream, " label=\"%s\"/>\n", vallab);
425       fprintf (stream, "/>\n");
426       if (!match_byte (1) && !match_byte(2))
427         match_byte_assert (3);
428     }
429   else if (match_byte (4))
430     {
431       unsigned int format;
432       char *var, *vallab, *value;
433
434       match_byte_assert (0x58);
435       format = get_u32 ();
436       vallab = get_string ();
437       var = get_string ();
438       if (!match_byte(1) && !match_byte(2))
439         match_byte_assert (3);
440       value = get_string ();
441       fprintf (stream, "<string-datum value=\"%s\" format=\"%s%d.%d\"",
442               value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
443       if (var[0])
444         fprintf (stream, " variable=\"%s\"", var);
445       if (vallab[0])
446         fprintf (stream, " label=\"%s\"/>\n", vallab);
447       fprintf (stream, "/>\n");
448     }
449   else if (match_byte (1))
450     {
451       unsigned int format;
452       double value;
453
454       dump_value_31(stream);
455       format = get_u32 ();
456       value = get_double ();
457       fprintf (stream, "<number value=\"%.*g\" format=\"%s%d.%d\"/>\n",
458                DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
459       if (match1)
460         match_byte (1);
461     }
462   else
463     {
464       dump_value_31(stream);
465
466       char *base = get_string();
467       int x = get_u32();
468       fprintf (stream, "<template format=\"%s\">\n", base);
469       for (int i = 0; i < x; i++)
470         {
471           int y = get_u32();
472           if (!y)
473             y = 1;
474           else
475             match_u32_assert(0);
476           for (int j = 0; j <= level + 1; j++)
477             fprintf (stream, "    ");
478           fprintf (stream, "<substitution index=\"%d\">\n", i + 1);
479           for (int j = 0; j < y; j++)
480             dump_value (stream, level + 2, false);
481           for (int j = 0; j <= level + 1; j++)
482             fprintf (stream, "    ");
483           fprintf (stream, "</substitution>\n");
484         }
485       for (int j = 0; j <= level; j++)
486         fprintf (stream, "    ");
487       fprintf (stream, "</template>\n");
488     }
489 }
490
491 static int
492 compare_int(const void *a_, const void *b_)
493 {
494   const int *a = a_;
495   const int *b = b_;
496   return *a < *b ? -1 : *a > *b;
497 }
498
499 static void
500 check_permutation(int *a, int n, const char *name)
501 {
502   int b[n];
503   memcpy(b, a, n * sizeof *a);
504   qsort(b, n, sizeof *b, compare_int);
505   for (int i = 0; i < n; i++)
506     if (b[i] != i)
507       {
508         fprintf(stderr, "bad %s permutation:", name);
509         for (int i = 0; i < n; i++)
510           fprintf(stderr, " %d", a[i]);
511         putc('\n', stderr);
512         exit(1);
513       }
514 }
515
516 static void
517 dump_category(int level, int *indexes, int *n_indexes)
518 {
519   for (int i = 0; i <= level; i++)
520     fprintf (stdout, "    ");
521   printf ("<category>\n");
522   dump_value (stdout, level + 1, true);
523   match_byte(0);
524   match_byte(0);
525   match_byte(0);
526
527   if (match_u32 (1))
528     match_byte (0);
529   else if (match_byte (1))
530     {
531       match_byte (0);
532       if (!match_u32 (2))
533         match_u32_assert (1);
534       match_byte (0);
535     }
536   else if (!match_u32(2))
537     match_u32_assert (0);
538
539   int indx = get_u32();
540   int n_categories = get_u32();
541   if (indx != -1)
542     {
543       if (n_categories != 0)
544         {
545           fprintf(stderr, "index not -1 but subcategories\n");
546           exit(1);
547         }
548       indexes[(*n_indexes)++] = indx;
549     }
550   if (n_categories == 0)
551     {
552       for (int i = 0; i <= level + 1; i++)
553         fprintf (stdout, "    ");
554       fprintf (stdout, "<category-index>%d</category-index>\n", indx);
555     }
556   for (int i = 0; i < n_categories; i++)
557     dump_category (level + 1, indexes, n_indexes);
558   for (int i = 0; i <= level; i++)
559     fprintf (stdout, "    ");
560   printf ("</category>\n");
561 }
562
563 static void
564 dump_dim(int indx)
565 {
566   int n_categories;
567
568   printf ("<dimension index=\"%d\">\n", indx);
569   dump_value (stdout, 0, false);
570
571   /* This byte is usually 0x02 but 0x00 and 0x75 (!) have also been spotted. */
572   pos++;
573
574   if (!match_byte(0) && !match_byte(1))
575     match_byte_assert(2);
576   if (!match_u32(0))
577     match_u32_assert(2);
578   if (!match_byte(0))
579     match_byte_assert(1);
580   if (!match_byte(0))
581     match_byte_assert(1);
582   match_byte_assert(1);
583   match_u32_assert(indx);
584   n_categories = get_u32();
585
586   int indexes[1024];
587   int n_indexes = 0;
588   for (int i = 0; i < n_categories; i++)
589     dump_category (0, indexes, &n_indexes);
590   check_permutation(indexes, n_indexes, "categories");
591
592   fprintf (stdout, "</dimension>\n");
593 }
594
595 int n_dims;
596 static void
597 dump_dims(void)
598 {
599   n_dims = get_u32();
600   for (int i = 0; i < n_dims; i++)
601     dump_dim (i);
602 }
603
604 static void
605 dump_data(void)
606 {
607   /* The first three numbers add to the number of dimensions. */
608   int t = get_u32();
609   t += get_u32();
610   match_u32_assert(n_dims - t);
611
612   /* The next n_dims numbers are a permutation of the dimension numbers. */
613   int a[n_dims];
614   for (int i = 0; i < n_dims; i++)
615     a[i] = get_u32();
616   check_permutation(a, n_dims, "dimensions");
617
618   int x = get_u32();
619   printf ("<data>\n");
620   for (int i = 0; i < x; i++)
621     {
622       printf ("    <datum index=\"%d\">\n", get_u32());
623       match_u32_assert(0);
624       dump_value(stdout, 1, false);
625       fprintf (stdout, "    </datum>\n");
626     }
627   printf ("</data>\n");
628 }
629
630 static void
631 dump_title(void)
632 {
633   pos = 0x27;
634   printf ("<title-local>\n");
635   dump_value(stdout, 0, true);
636   printf ("</title-local>\n");
637
638   printf ("<subtype>\n");
639   dump_value(stdout, 0, true);
640   printf ("</subtype>\n");
641
642   match_byte_assert(0x31);
643
644   printf ("<title-c>\n");
645   dump_value(stdout, 0, true);
646   printf ("</title-c>\n");
647
648   match_byte(0);
649   match_byte_assert(0x58);
650   if (match_byte(0x31))
651     {
652       printf ("<caption>\n");
653       dump_value(stdout, 0, false);
654       printf ("</caption>\n");
655     }
656   else
657     match_byte_assert(0x58);
658
659
660   int n_footnotes = get_u32();
661   for (int i = 0; i < n_footnotes; i++)
662     {
663       printf ("<footnote index=\"%d\">\n", i);
664       dump_value(stdout, 0, false);
665       if (match_byte (0x31))
666         {
667           /* Custom footnote marker string. */
668           match_byte_assert(3);
669           get_string();
670           match_byte_assert(0x58);
671           match_u32_assert(0);
672           get_string();
673         }
674       else
675         match_byte_assert (0x58);
676       printf("(%d)\n", get_u32());
677       printf ("</footnote>\n");
678     }
679 }
680
681 static void
682 dump_fonts(void)
683 {
684   match_byte(0);
685   for (int i = 1; i <= 8; i++)
686     {
687       printf ("<style index=\"%d\"", i);
688       match_byte_assert(i);
689       match_byte_assert(0x31);
690       printf(" font=\"%s\"", get_string());
691       match_byte_assert(0);
692       match_byte_assert(0);
693       if (!match_byte(0x40) && !match_byte(0x20) && !match_byte(0x80) && !match_byte(0x10))
694         match_byte_assert(0x50);
695       if (!match_byte(0x41))
696         match_byte_assert(0x51);
697       if (!match_u32(0))
698         match_u32_assert(1);
699       match_byte_assert(0);
700
701       /* OK, this seems really unlikely to be totally correct, but it matches my corpus... */
702       if (!match_u32(0) && !match_u32(2))
703         match_u32_assert(0xfaad);
704
705       if (!match_u32(0) && !match_u32(1) && !match_u32(2))
706         match_u32_assert(3);
707       printf (" fgcolor=\"%s\"", get_string());
708       printf (" bgcolor=\"%s\"", get_string());
709       match_u32_assert(0);
710       match_u32_assert(0);
711       match_byte_assert(0);
712
713       /* These seem unlikely to be correct too. */
714       if (i != 3)
715         {
716           match_u32_assert(8);
717           if (!match_u32(10))
718             match_u32_assert(11);
719           match_u32_assert(1);
720         }
721       else
722         {
723           get_u32();
724           if (!match_u32(-1) && !match_u32(8))
725             match_u32_assert(24);
726           if (!match_u32(-1) && !match_u32(2))
727             match_u32_assert(3);
728         }
729
730       /* Who knows? Ranges from -1 to 8 with no obvious pattern. */
731       get_u32();
732
733       printf ("/>\n");
734     }
735
736   match_u32_assert(240);
737   pos += 240;
738
739   match_u32_assert(18);
740   pos += 18;
741
742   if (match_u32(117))
743     pos += 117;
744   else
745     {
746       match_u32_assert(142);
747       pos += 142;
748     }
749
750   int count = get_u32();
751   pos += 4 * count;
752
753   printf ("<encoding>%s</encoding>\n", get_string ());
754
755   if (!match_u32(0))
756     match_u32_assert(UINT32_MAX);
757   if (!match_byte(0))
758     match_byte_assert(1);
759   match_byte_assert(0);
760   if (!match_byte(0))
761     match_byte_assert(1);
762   if (!match_byte(0x97) && !match_byte(0x98) && !match_byte(0x99))
763     match_byte_assert(0x9a);
764   match_byte_assert(7);
765   match_byte_assert(0);
766   match_byte_assert(0);
767   if (match_byte('.'))
768     match_byte_assert(',');
769   else
770     {
771       match_byte_assert(',');
772       if (!match_byte('.'))
773         match_byte_assert(' ');
774     }
775   match_u32_assert(5);
776   for (int i = 0; i < 5; i++)
777     get_string();
778   pos += get_u32();
779 }
780
781 int
782 main(int argc, char *argv[])
783 {
784   size_t start;
785   struct stat s;
786
787   if (isatty(STDIN_FILENO))
788     {
789       fprintf(stderr, "redirect stdin from a .bin file\n");
790       exit(1);
791     }
792   if (fstat(STDIN_FILENO, &s))
793     {
794       perror("fstat");
795       exit(1);
796     }
797   n = s.st_size;
798   data = malloc(n);
799   if (!data)
800     {
801       perror("malloc");
802       exit(1);
803     }
804   if (read(STDIN_FILENO, data, n) != n)
805     {
806       perror("read");
807       exit(1);
808     }
809
810   if (argc > 1)
811     {
812       if (!strcmp(argv[1], "title0"))
813         {
814           pos = 0x27;
815           if (match_byte (0x03)
816               || (match_byte (0x05) && match_byte (0x58)))
817             printf ("%s\n", get_string());
818           else
819             printf ("<unknown>\n");
820           return 0;
821         }
822       else if (!strcmp(argv[1], "title"))
823         {
824           dump_title();
825           exit(0);
826         }
827       else if (!strcmp(argv[1], "titleraw"))
828         {
829           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
830           start = 0x27;
831           n = find(fonts, sizeof fonts - 1);
832         }
833       else if (!strcmp(argv[1], "fonts"))
834         {
835           const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
836           const char styles[] = "\xf0\0\0\0";
837           start = find(fonts, sizeof fonts - 1);
838           n = find(styles, sizeof styles - 1);
839         }
840       else if (!strcmp(argv[1], "styles"))
841         {
842           const char styles[] = "\xf0\0\0\0";
843           const char dimensions[] = "-,,,.\0";
844           start = find(styles, sizeof styles - 1);
845           n = find(dimensions, sizeof dimensions - 1) + sizeof dimensions - 1;
846         }
847       else if (!strcmp(argv[1], "dimensions") || !strcmp(argv[1], "all"))
848         {
849           pos = 0;
850           match_byte_assert(1);
851           match_byte_assert(0);
852           match_u32_assert(3);
853           match_byte_assert(1);
854           if (!match_byte(0))
855             match_byte_assert(1);
856           match_byte_assert(0);
857           match_byte_assert(0);
858           if (!match_byte(0))
859             match_byte_assert(1);
860           pos++;
861           match_byte_assert(0);
862           match_byte_assert(0);
863           match_byte_assert(0);
864           dump_title ();
865           dump_fonts();
866           dump_dims ();
867           dump_data ();
868           match_byte (1);
869           if (pos != n)
870             {
871               fprintf (stderr, "%x / %x\n", pos, n);
872               exit(1);
873             }
874           exit(0);
875         }
876       else
877         {
878           fprintf (stderr, "unknown section %s\n", argv[1]);
879           exit(1);
880         }
881     }
882   else
883     start = 0x27;
884
885   dump_raw(stdout, start, n);
886
887   return 0;
888 }