13 all_ascii(const uint8_t *p, size_t n)
15 for (size_t i = 0; i < n; i++)
16 if (p[i] < 32 || p[i] > 126)
22 try_find(const char *target, size_t target_len)
24 const uint8_t *pos = (const uint8_t *) memmem (data, n, target, target_len);
25 return pos ? pos - data : 0;
29 try_find_tail(const char *target, size_t target_len)
31 size_t pos = try_find(target, target_len);
32 return pos ? pos + target_len : 0;
36 find(const char *target, size_t target_len)
38 size_t pos = try_find(target, target_len);
41 fprintf (stderr, "not found\n");
48 find_tail(const char *target, size_t target_len)
50 size_t pos = try_find_tail(target, target_len);
53 fprintf (stderr, "not found\n");
62 #define STR(x) XSTR(x)
63 #define WHERE __FILE__":" STR(__LINE__)
69 memcpy(&x, &data[pos], 4);
78 memcpy(&x, &data[pos], 8);
93 match_u32_assert(uint32_t x, const char *where)
95 unsigned int y = get_u32();
98 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
102 #define match_u32_assert(x) match_u32_assert(x, WHERE)
105 match_byte(uint8_t b)
107 if (pos < n && data[pos] == b)
117 match_byte_assert(uint8_t b, const char *where)
121 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
125 #define match_byte_assert(b) match_byte_assert(b, WHERE)
128 get_string(const char *where)
131 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
132 /*&& all_ascii(&data[pos + 4], data[pos])*/)
134 int len = data[pos] + data[pos + 1] * 256;
135 char *s = malloc(len + 1);
137 memcpy(s, &data[pos + 4], len);
144 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
148 #define get_string() get_string(WHERE)
153 if (match_byte (0x31))
160 match_u32_assert (0);
161 int subn = get_u32 ();
162 printf ("nested %d bytes", subn);
165 else if (match_u32 (1))
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);
174 else if (match_u32 (2))
176 printf("(special 2)");
177 match_byte_assert(0);
178 match_byte_assert(0);
180 match_byte_assert(0);
181 match_byte_assert(0);
182 int subn = get_u32 ();
183 printf ("nested %d bytes", subn);
189 printf("(special 3)");
190 match_byte_assert(0);
191 match_byte_assert(0);
192 match_byte_assert(1);
193 match_byte_assert(0);
194 int subn = get_u32 ();
195 printf ("nested %d bytes, ", subn);
198 printf ("nested %d bytes, ", subn);
203 match_byte_assert (0x58);
207 dump_value(int level)
209 for (int i = 0; i <= level; i++)
218 char *s1 = get_string();
220 char *s2 = get_string();
221 char *s3 = get_string();
223 printf("strings \"%s\", \"%s\" and \"%s\"", s1, s2, s3);
225 printf("string \"%s\" and \"%s\"", s1, s2);
233 else if (match_byte (5))
235 match_byte_assert (0x58);
236 printf ("variable \"%s\"", get_string());
238 if (!match_byte(1) && !match_byte(2))
239 match_byte_assert(3);
244 else if (match_byte (2))
250 match_byte_assert (0x58);
252 value = get_double ();
254 vallab = get_string ();
255 printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
256 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
257 if (!match_byte (1) && !match_byte(2))
258 match_byte_assert (3);
263 else if (match_byte (4))
266 char *var, *vallab, *value;
268 match_byte_assert (0x58);
270 vallab = get_string ();
272 if (!match_byte(1) && !match_byte(2))
273 match_byte_assert (3);
274 value = get_string ();
275 printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
276 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
281 else if (match_byte (1))
288 value = get_double ();
289 printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
298 char *base = get_string();
300 printf ("\"%s\" with %d variables:\n", base, x);
303 for (int i = 0; i < x; i++)
305 dump_value (level+1);
311 for (int i = 0; i < x; i++)
315 for (int j = 0; j <= level; j++)
317 printf("variable %d has %d values:\n", i, y);
318 for (int j = 0; j < y; j++)
322 char *a = get_string();
323 match_byte_assert(0x58);
324 char *b = get_string();
325 char *c = get_string();
326 for (int k = 0; k <= level + 1; k++)
328 printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
336 dump_value (level+1);
345 dump_dim_value(int level)
347 for (int i = 0; i <= level; i++)
355 printf("string \"%s\"", get_string());
359 else if (match_byte (5))
361 match_byte_assert (0x58);
362 printf ("variable \"%s\"", get_string());
365 match_byte_assert(3);
367 else if (match_byte (2))
373 match_byte_assert (0x58);
375 value = get_double ();
377 vallab = get_string ();
378 printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
379 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
381 match_u32_assert (2);
384 else if (match_byte (1))
389 match_byte_assert (0x58);
391 value = get_double ();
392 printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
403 printf ("; \"%s\", substitutions:", get_string());
404 int total_subs = get_u32();
408 total_subs = (total_subs - 1) + x;
409 match_u32_assert (0);
411 printf (" (total %d)", total_subs);
413 for (int i = 0; i < total_subs; i++)
416 dump_value (level + 1);
422 dump_category(int level)
432 else if (match_u32 (1))
439 else if (match_byte (1))
443 match_u32_assert (1);
449 match_u32_assert (0);
453 int n_categories = get_u32();
454 if (n_categories > 0)
455 printf (", %d subcategories:", n_categories);
457 for (int i = 0; i < n_categories; i++)
458 dump_category (level + 1);
465 printf("next dim\n");
469 /* This byte is usually 0x02 but 0x00 and 0x75 (!) have also been spotted. */
472 if (!match_byte(0) && !match_byte(1))
473 match_byte_assert(2);
477 match_byte_assert(1);
487 n_categories = get_u32();
488 printf("%d nested categories\n", n_categories);
489 for (int i = 0; i < n_categories; i++)
498 printf ("%u dimensions\n", n_dims);
499 for (int i = 0; i < n_dims; i++)
507 dump_data_value(void)
520 value = get_double ();
521 printf (" value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
523 else if (match_byte (3))
528 printf("string \"%s\"", get_string());
531 else if (match_byte (2))
537 match_byte_assert (0x58);
539 value = get_double ();
541 vallab = get_string ();
542 printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
543 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
544 if (!match_byte (1) && !match_byte(2))
545 match_byte_assert (3);
547 else if (match_byte (4))
550 char *var, *vallab, *value;
552 match_byte_assert (0x58);
554 vallab = get_string ();
556 if (!match_byte(1) && !match_byte(2))
557 match_byte_assert (3);
558 value = get_string ();
559 printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
560 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
562 else if (match_byte (5))
564 match_byte_assert (0x58);
565 printf ("variable \"%s\"", get_string());
567 if (!match_byte(1) && !match_byte(2))
568 match_byte_assert(3);
577 char *base = get_string();
579 printf ("\"%s\"; %d variables:\n", base, x);
580 for (int i = 0; i < x; i++)
587 for (int j = 0; j <= 0; j++)
589 printf("variable %d has %d values:\n", i, y);
590 for (int j = 0; j < y; j++)
601 for (int i = 0; i < 3 + n_dims; i++)
603 printf ("data intro:");
604 for (int i = 0; i < 3 + n_dims; i++)
608 fprintf (stderr,"data intro (%d dims):", n_dims);
609 for (int i = 0; i < 3+n_dims; i++)
610 fprintf (stderr," %d", get_u32());
611 fprintf(stderr,"\n");
614 printf ("%d data values, starting at %08x\n", x, pos);
615 for (int i = 0; i < x; i++)
617 printf("%08x, index %d:\n", pos, get_u32());
625 dump_title_value_31(int level)
627 if (match_byte (0x31))
631 match_u32_assert (0);
632 int subn = get_u32 ();
633 printf ("nested %d bytes", subn);
636 else if (match_u32 (1))
638 printf("(footnote %d) ", get_u32());
639 match_byte_assert (0);
640 match_byte_assert (0);
641 int subn = get_u32 ();
642 printf ("nested %d bytes", subn);
645 else if (match_u32 (2))
647 printf("(special 2)");
648 match_byte_assert(0);
649 match_byte_assert(0);
652 match_byte_assert(0);
653 match_byte_assert(0);
654 int subn = get_u32 ();
655 printf ("nested %d bytes", subn);
661 printf("(special 3)");
662 match_byte_assert(0);
663 match_byte_assert(0);
664 match_byte_assert(1);
665 match_byte_assert(0);
666 int subn = get_u32 ();
667 printf ("nested %d bytes, ", subn);
670 printf ("nested %d bytes, ", subn);
675 match_byte_assert (0x58);
679 dump_title_value(int level)
681 for (int i = 0; i <= level; i++)
692 dump_title_value_31(level);
694 printf("string \"%s\"", get_string());
705 else if (match_byte (5))
707 dump_title_value_31(level);
708 printf ("variable \"%s\"", get_string());
710 if (!match_byte(1) && !match_byte(2))
711 match_byte_assert(3);
713 else if (match_byte (2))
719 match_byte_assert (0x58);
721 value = get_double ();
723 vallab = get_string ();
724 printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
725 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
726 if (!match_byte (1) && !match_byte(2))
727 match_byte_assert (3);
736 else if (match_byte (4))
739 char *var, *vallab, *value;
741 match_byte_assert (0x58);
743 vallab = get_string ();
745 if (!match_byte(1) && !match_byte(2))
746 match_byte_assert (3);
747 value = get_string ();
748 printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
749 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
755 else if (match_byte (1))
760 dump_title_value_31(level);
762 value = get_double ();
763 printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
772 dump_title_value_31(level);
774 char *base = get_string();
776 printf ("\"%s\" with %d variables:\n", base, x);
777 for (int i = 0; i < x; i++)
784 for (int j = 0; j <= level; j++)
786 printf("variable %d has %d values:\n", i, y);
787 for (int j = 0; j < y; j++)
792 char *a = get_string();
793 match_byte_assert(0x58);
794 char *b = get_string();
795 char *c = get_string();
796 for (int k = 0; k <= level + 1; k++)
798 printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
801 dump_title_value (level+1);
809 dump_footnote_value_31(void)
811 if (match_byte (0x31))
816 match_u32_assert (0);
817 int subn = get_u32 ();
818 printf ("nested %d bytes", subn);
821 else if (match_u32 (1))
823 printf("(footnote %d) ", get_u32());
824 match_byte_assert (0);
825 match_byte_assert (0);
826 int subn = get_u32 ();
827 printf ("nested %d bytes", subn);
830 else if (match_u32 (2))
832 printf("(special 2)");
833 match_byte_assert(0);
834 match_byte_assert(0);
836 match_byte_assert(0);
837 match_byte_assert(0);
838 int subn = get_u32 ();
839 printf ("nested %d bytes", subn);
845 printf("(special 3)");
846 match_byte_assert(0);
847 match_byte_assert(0);
848 match_byte_assert(1);
849 match_byte_assert(0);
850 int subn = get_u32 ();
851 printf ("nested %d bytes, ", subn);
854 printf ("nested %d bytes, ", subn);
859 match_byte_assert (0x58);
863 dump_footnote_value(int level)
865 for (int i = 0; i <= level; i++)
875 dump_footnote_value_31();
877 printf("string \"%s\"", get_string());
879 match_byte_assert (1);
881 else if (match_byte (5))
883 match_byte_assert (0x58);
884 printf ("variable \"%s\"", get_string());
886 if (!match_byte(1) && !match_byte(2))
887 match_byte_assert(3);
889 else if (match_byte (2))
895 match_byte_assert (0x58);
897 value = get_double ();
899 vallab = get_string ();
900 printf ("value %g format %d(%d.%d) var \"%s\" vallab \"%s\"",
901 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
902 if (!match_byte (1) && !match_byte(2))
903 match_byte_assert (3);
912 else if (match_byte (4))
915 char *var, *vallab, *value;
917 match_byte_assert (0x58);
919 vallab = get_string ();
921 if (!match_byte(1) && !match_byte(2))
922 match_byte_assert (3);
923 value = get_string ();
924 printf ("value \"%s\" format %d(%d.%d) var \"%s\" vallab \"%s\"",
925 value, format >> 16, (format >> 8) & 0xff, format & 0xff, var, vallab);
931 else if (match_byte (1))
936 dump_footnote_value_31();
938 value = get_double ();
939 printf ("value %g format %d(%d.%d)", value, format >> 16, (format >> 8) & 0xff, format & 0xff);
943 dump_footnote_value_31();
944 char *base = get_string();
946 printf ("\"%s\"; %d variables:\n", base, x);
947 for (int i = 0; i < x; i++)
954 for (int j = 0; j <= level; j++)
956 printf("variable %d has %d values:\n", i, y);
957 for (int j = 0; j < y; j++)
961 char *a = get_string();
962 match_byte_assert(0x58);
963 char *b = get_string();
964 char *c = get_string();
965 for (int k = 0; k <= level + 1; k++)
967 printf ("\"%s\", \"%s\", \"%s\"", a, b, c);
969 match_byte_assert(0);
972 dump_footnote_value (level+1);
983 dump_title_value(0); putchar('\n');
984 dump_title_value(0); putchar('\n');
985 match_byte_assert(0x31);
986 dump_title_value(0); putchar('\n');
988 match_byte_assert(0x58);
989 if (match_byte(0x31))
991 dump_footnote_value(0); putchar('\n');
994 match_byte_assert(0x58);
997 int n_footnotes = get_u32();
998 if (n_footnotes >= 20)
1000 fprintf(stderr, "%08x: %d footnotes\n", pos - 4, n_footnotes);
1004 printf("------\n%d footnotes\n", n_footnotes);
1005 if (n_footnotes < 20)
1007 for (int i = 0; i < n_footnotes; i++)
1009 printf("footnote %d:\n", i);
1010 dump_footnote_value(0);
1015 if (match_byte (0x31))
1017 /* Custom footnote marker string. */
1018 match_byte_assert(3);
1020 match_byte_assert(0x58);
1021 match_u32_assert(0);
1025 match_byte_assert (0x58);
1026 printf("(%d)\n", get_u32());
1032 find_dimensions(void)
1035 const char dimensions[] = "-,,,.\0";
1036 int x = try_find_tail(dimensions, sizeof dimensions - 1);
1041 const char dimensions[] = "-,,, .\0";
1042 return find_tail(dimensions, sizeof dimensions - 1);
1048 printf("fonts: offset=%08x\n", pos);
1050 for (int i = 1; i <= 8; i++)
1052 printf("%08x: font %d, ", pos, i);
1053 match_byte_assert(i);
1054 match_byte_assert(0x31);
1055 printf("%s, ", get_string());
1056 match_byte_assert(0);
1057 match_byte_assert(0);
1058 if (!match_byte(0x40) && !match_byte(0x20) && !match_byte(0x80) && !match_byte(0x10))
1059 match_byte_assert(0x50);
1060 if (!match_byte(0x41))
1061 match_byte_assert(0x51);
1063 printf ("%s, ", get_string());
1064 printf ("%s, ", get_string());
1065 match_u32_assert(0);
1066 match_u32_assert(0);
1075 match_u32_assert(240);
1078 match_u32_assert(18);
1085 match_u32_assert(142);
1089 int count = get_u32();
1092 char *encoding = get_string();
1093 printf("encoding=%s\n", encoding);
1096 match_u32_assert(UINT32_MAX);
1098 match_byte_assert(1);
1099 match_byte_assert(0);
1101 match_byte_assert(1);
1102 if (!match_byte(0x99) && !match_byte(0x98))
1103 match_byte_assert(0x97);
1104 match_byte_assert(7);
1105 match_byte_assert(0);
1106 match_byte_assert(0);
1107 if (match_byte('.'))
1108 match_byte_assert(',');
1111 match_byte_assert(',');
1112 if (!match_byte('.'))
1113 match_byte_assert(' ');
1115 match_u32_assert(5);
1116 for (int i = 0; i < 5; i++)
1119 if (pos != find_dimensions())
1120 fprintf (stderr, "%08x / %08x\n", pos, find_dimensions());
1124 main(int argc, char *argv[])
1129 if (isatty(STDIN_FILENO))
1131 fprintf(stderr, "redirect stdin from a .bin file\n");
1134 if (fstat(STDIN_FILENO, &s))
1146 if (read(STDIN_FILENO, data, n) != n)
1154 if (!strcmp(argv[1], "title0"))
1157 if (match_byte (0x03)
1158 || (match_byte (0x05) && match_byte (0x58)))
1159 printf ("%s\n", get_string());
1161 printf ("<unknown>\n");
1164 else if (!strcmp(argv[1], "title"))
1169 else if (!strcmp(argv[1], "titleraw"))
1171 const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1173 n = find(fonts, sizeof fonts - 1);
1175 else if (!strcmp(argv[1], "fonts"))
1177 const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1178 const char styles[] = "\xf0\0\0\0";
1179 start = find(fonts, sizeof fonts - 1);
1180 n = find(styles, sizeof styles - 1);
1182 else if (!strcmp(argv[1], "styles"))
1184 const char styles[] = "\xf0\0\0\0";
1185 const char dimensions[] = "-,,,.\0";
1186 start = find(styles, sizeof styles - 1);
1187 n = find(dimensions, sizeof dimensions - 1) + sizeof dimensions - 1;
1189 else if (!strcmp(argv[1], "dimensions") || !strcmp(argv[1], "all"))
1192 match_byte_assert(1);
1193 match_byte_assert(0);
1194 match_u32_assert(3);
1195 match_byte_assert(1);
1197 match_byte_assert(1);
1198 match_byte_assert(0);
1199 match_byte_assert(0);
1201 match_byte_assert(1);
1203 match_byte_assert(0);
1204 match_byte_assert(0);
1205 match_byte_assert(0);
1209 printf("\n\ndata:\n");
1212 match_byte_assert (1);
1215 fprintf (stderr, "%x / %x\n", pos, n);
1222 fprintf (stderr, "unknown section %s\n", argv[1]);
1229 for (size_t i = start; i < n; )
1236 && i + 4 + data[i] + data[i + 1] * 256 <= n
1237 && all_ascii(&data[i + 4], data[i] + data[i + 1] * 256))
1239 fputs("\n\"", stdout);
1240 fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stdout);
1241 fputs("\" ", stdout);
1243 i += 4 + data[i] + data[i + 1] * 256;
1245 else if (i + 12 <= n
1246 && data[i + 1] == 40
1248 && data[i + 3] == 0)
1252 memcpy (&d, &data[i + 4], 8);
1253 printf ("F40.%d(%.*f)\n", data[i], data[i], d);
1256 else if (i + 12 <= n
1257 && data[i + 1] == 40
1258 && data[i + 2] == 31
1259 && data[i + 3] == 0)
1263 memcpy (&d, &data[i + 4], 8);
1264 printf ("PCT40.%d(%.*f)\n", data[i], data[i], d);
1268 && (data[i] && data[i] != 88 && data[i] != 0x41)
1273 printf ("i%d ", data[i]);
1278 printf("%02x ", data[i]);