11 #include "u8-mbtouc.h"
19 all_ascii(const uint8_t *p, size_t n)
21 for (size_t i = 0; i < n; i++)
22 if (p[i] < 32 || p[i] > 126)
28 try_find(const char *target, size_t target_len)
30 const uint8_t *pos = (const uint8_t *) memmem (data, n, target, target_len);
31 return pos ? pos - data : 0;
35 find(const char *target, size_t target_len)
37 size_t pos = try_find(target, target_len);
40 fprintf (stderr, "not found\n");
49 #define STR(x) XSTR(x)
50 #define WHERE __FILE__":" STR(__LINE__)
62 memcpy(&x, &data[pos], 4);
67 static unsigned long long int
71 memcpy(&x, &data[pos], 8);
80 x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
89 memcpy(&x, &data[pos], 2);
98 memcpy(&x, &data[pos], 8);
103 static double __attribute__((unused))
107 memcpy(&x, &data[pos], 4);
113 match_u32(uint32_t x)
122 match_u32_assert(uint32_t x, const char *where)
124 unsigned int y = get_u32();
127 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
131 #define match_u32_assert(x) match_u32_assert(x, WHERE)
133 static bool __attribute__((unused))
134 match_u64(uint64_t x)
142 static void __attribute__((unused))
143 match_u64_assert(uint64_t x, const char *where)
145 unsigned long long int y = get_u64();
148 fprintf(stderr, "%s: 0x%x: expected u64:%llu, got u64:%llu\n", where, pos - 8, x, y);
152 #define match_u64_assert(x) match_u64_assert(x, WHERE)
154 static bool __attribute__((unused))
155 match_be32(uint32_t x)
164 match_be32_assert(uint32_t x, const char *where)
166 unsigned int y = get_be32();
169 fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
173 #define match_be32_assert(x) match_be32_assert(x, WHERE)
176 match_byte(uint8_t b)
178 if (pos < n && data[pos] == b)
188 match_byte_assert(uint8_t b, const char *where)
192 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
196 #define match_byte_assert(b) match_byte_assert(b, WHERE)
203 match_byte_assert(1);
208 newline(FILE *stream, int pos)
210 fprintf(stream, "\n%08x: ", pos);
214 dump_raw(FILE *stream, int start, int end)
216 for (size_t i = start; i < end; )
223 && i + 4 + data[i] + data[i + 1] * 256 <= end
224 && all_ascii(&data[i + 4], data[i] + data[i + 1] * 256))
227 fprintf(stream, "\"");
228 fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stream);
229 fputs("\" ", stream);
231 i += 4 + data[i] + data[i + 1] * 256;
233 else if (i + 12 <= end
240 memcpy (&d, &data[i + 4], 8);
241 fprintf (stream, "F40.%d(%.*f)", data[i], data[i], d);
245 else if (i + 12 <= end
252 memcpy (&d, &data[i + 4], 8);
253 fprintf (stream, "PCT40.%d(%.*f)", data[i], data[i], d);
257 else if (i + 4 <= end
258 && (data[i] && data[i] != 88 && data[i] != 0x41)
263 fprintf (stream, "i%d ", data[i]);
268 fprintf(stream, "%02x ", data[i]);
276 static bool __attribute__((unused))
277 all_utf8(const char *p_)
279 const uint8_t *p = (const uint8_t *) p_;
280 size_t len = strlen ((char *) p);
281 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
285 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
286 if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
293 get_string(const char *where)
296 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
297 /*&& all_ascii(&data[pos + 4], data[pos])*/)
299 int len = data[pos] + data[pos + 1] * 256;
300 char *s = malloc(len + 1);
302 memcpy(s, &data[pos + 4], len);
309 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
313 #define get_string() get_string(WHERE)
316 get_string_be(const char *where)
319 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
320 /*&& all_ascii(&data[pos + 4], data[pos])*/)
322 int len = data[pos + 2] * 256 + data[pos + 3];
323 char *s = malloc(len + 1);
325 memcpy(s, &data[pos + 4], len);
332 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
336 #define get_string_be() get_string_be(WHERE)
345 static void __attribute__((unused))
346 hex_dump(int ofs, int n)
348 for (int i = 0; i < n; i++)
350 int c = data[ofs + i];
359 for (int i = 0; i < n; i++)
361 int c = data[ofs + i];
362 printf("%c", c >= 32 && c < 127 ? c : '.');
367 dump_counted_string(void)
369 int inner_end = get_end();
370 if (pos == inner_end)
376 match_byte_assert(0x58);
382 if (match_byte(0x31))
385 match_byte_assert(0x58);
386 if (pos != inner_end)
388 fprintf(stderr, "inner end discrepancy\n");
395 dump_style(FILE *stream)
397 if (match_byte(0x58))
400 match_byte_assert(0x31);
402 printf (" bold=\"yes\"");
404 printf (" italic=\"yes\"");
406 printf (" underline=\"yes\"");
408 printf (" show=\"no\"");
409 char *fg = get_string(); /* foreground */
410 char *bg = get_string(); /* background */
411 char *font = get_string(); /* font */
412 int size = get_byte() * (72. / 96.);
413 fprintf(stream, " fgcolor=\"%s\" bgcolor=\"%s\" font=\"%s\" size=\"%dpt\"",
418 dump_style2(FILE *stream)
420 if (match_byte(0x58))
423 match_byte_assert(0x31);
424 uint32_t halign = get_u32();
425 printf (" halign=\"%s\"",
426 halign == 0 ? "center"
427 : halign == 2 ? "left"
428 : halign == 4 ? "right"
429 : halign == 6 ? "decimal"
430 : halign == 0xffffffad ? "mixed"
432 int valign = get_u32();
433 printf (" valign=\"%s\"",
434 valign == 0 ? "center"
435 : valign == 1 ? "top"
436 : valign == 3 ? "bottom"
438 printf (" offset=\"%gpt\"", get_double());
443 printf (" margins=\"%d %d %d %d\"", l, r, t, b);
447 dump_nested_string(FILE *stream)
451 match_byte_assert (0);
452 match_byte_assert (0);
453 int outer_end = get_end();
454 s = dump_counted_string();
456 fprintf(stream, " \"%s\"", s);
458 match_byte_assert(0x58);
459 if (pos != outer_end)
461 fprintf(stderr, "outer end discrepancy\n");
469 dump_value_modifier(FILE *stream)
471 if (match_byte (0x31))
475 fprintf(stream, "<special0");
478 /* Corpus frequencies:
483 The given text is appended to the cell in a subscript font.
485 fprintf(stream, " subscript=\"%s\"", get_string());
488 match_u32_assert (0);
492 /* We only have one SPV file for this version (with many
499 if (!match_u32(0) && !match_u32(1) && !match_u32(2) && !match_u32(3) && !match_u32(4) && !match_u32(5) && !match_u32(6) && !match_u32(7) && !match_u32(8) && !match_u32(9))
500 match_u32_assert(10);
503 fprintf(stream, "/>\n");
507 int outer_end = get_end();
509 /* This counted-string appears to be a template string,
510 e.g. "Design\: [:^1:]1 Within Subjects Design\: [:^1:]2". */
511 char *template = dump_counted_string();
513 fprintf(stream, " template=\"%s\"", template);
517 if (pos != outer_end)
519 fprintf(stderr, "outer end discrepancy\n");
522 fprintf(stream, "/>\n");
526 int count = get_u32();
527 fprintf(stream, "<footnote-ref indexes=\"");
528 for (int i = 0; i < count; i++)
532 fprintf(stream, "%d", get_u16());
535 match_byte_assert(0);
536 match_byte_assert(0);
537 dump_nested_string(stream);
538 fprintf(stream, "/>\n");
542 match_byte_assert (0x58);
546 format_to_string (int type)
552 case 2: return "AHEX";
553 case 3: return "COMMA";
554 case 4: return "DOLLAR";
555 case 5: case 40: return "F";
557 case 7: return "PIBHEX";
559 case 9: return "PIB";
560 case 10: return "PK";
561 case 11: return "RB";
562 case 12: return "RBHEX";
566 case 20: return "DATE";
567 case 21: return "TIME";
568 case 22: return "DATETIME";
569 case 23: return "ADATE";
570 case 24: return "JDATE";
571 case 25: return "DTIME";
572 case 26: return "WKDAY";
573 case 27: return "MONTH";
574 case 28: return "MOYR";
575 case 29: return "QYR";
576 case 30: return "WKYR";
577 case 31: return "PCT";
578 case 32: return "DOT";
579 case 33: return "CCA";
580 case 34: return "CCB";
581 case 35: return "CCC";
582 case 36: return "CCD";
583 case 37: return "CCE";
584 case 38: return "EDATE";
585 case 39: return "SDATE";
588 sprintf(tmp, "<%d>", type);
594 dump_value(FILE *stream, int level)
601 for (int i = 0; i <= level; i++)
602 fprintf (stream, " ");
609 dump_value_modifier(stream);
611 value = get_double ();
612 fprintf (stream, "<number value=\"%.*g\" format=\"%s%d.%d\"/>\n",
613 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
615 else if (match_byte (2))
621 dump_value_modifier (stream);
623 value = get_double ();
625 vallab = get_string ();
626 fprintf (stream, "<numeric-datum value=\"%.*g\" format=\"%s%d.%d\"",
627 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
629 fprintf (stream, " variable=\"%s\"", var);
631 fprintf (stream, " label=\"%s\"", vallab);
632 fprintf (stream, "/>\n");
633 if (!match_byte (1) && !match_byte(2))
634 match_byte_assert (3);
636 else if (match_byte (3))
638 char *text = get_string();
639 dump_value_modifier(stream);
640 char *identifier = get_string();
641 char *text_eng = get_string();
642 fprintf (stream, "<string c=\"%s\"", text_eng);
644 fprintf (stream, " identifier=\"%s\"", identifier);
645 if (strcmp(text_eng, text))
646 fprintf (stream, " local=\"%s\"", text);
647 fprintf (stream, "/>\n");
649 match_byte_assert(1);
651 else if (match_byte (4))
654 char *var, *vallab, *value;
656 dump_value_modifier(stream);
658 vallab = get_string ();
660 if (!match_byte(1) && !match_byte(2))
661 match_byte_assert (3);
662 value = get_string ();
663 fprintf (stream, "<string-datum value=\"%s\" format=\"%s%d.%d\"",
664 value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
666 fprintf (stream, " variable=\"%s\"", var);
668 fprintf (stream, " label=\"%s\"/>\n", vallab);
669 fprintf (stream, "/>\n");
671 else if (match_byte (5))
673 dump_value_modifier(stream);
674 char *name = get_string ();
675 char *label = get_string ();
676 fprintf (stream, "<variable name=\"%s\"", name);
678 fprintf (stream, " label=\"%s\"", label);
679 fprintf (stream, "/>\n");
680 if (!match_byte(1) && !match_byte(2))
681 match_byte_assert(3);
685 dump_value_modifier(stream);
687 char *base = get_string();
689 fprintf (stream, "<template format=\"%s\">\n", base);
690 for (int i = 0; i < x; i++)
697 for (int j = 0; j <= level + 1; j++)
698 fprintf (stream, " ");
699 fprintf (stream, "<substitution index=\"%d\">\n", i + 1);
700 for (int j = 0; j < y; j++)
701 dump_value (stream, level + 2);
702 for (int j = 0; j <= level + 1; j++)
703 fprintf (stream, " ");
704 fprintf (stream, "</substitution>\n");
706 for (int j = 0; j <= level; j++)
707 fprintf (stream, " ");
708 fprintf (stream, "</template>\n");
713 compare_int(const void *a_, const void *b_)
717 return *a < *b ? -1 : *a > *b;
721 check_permutation(int *a, int n, const char *name)
724 memcpy(b, a, n * sizeof *a);
725 qsort(b, n, sizeof *b, compare_int);
726 for (int i = 0; i < n; i++)
729 fprintf(stderr, "bad %s permutation:", name);
730 for (int i = 0; i < n; i++)
731 fprintf(stderr, " %d", a[i]);
738 dump_category(FILE *stream, int level, int **indexes, int *allocated_indexes,
741 for (int i = 0; i <= level; i++)
742 fprintf (stream, " ");
743 printf ("<category>\n");
744 dump_value (stream, level + 1);
746 int merge = data[pos];
748 match_byte_assert (1);
750 match_byte_assert (0);
752 int unindexed = data[pos];
754 match_byte_assert (1);
759 match_u32_assert (2);
761 int indx = get_u32();
762 int n_categories = get_u32();
767 for (int i = 0; i <= level + 1; i++)
768 fprintf (stream, " ");
769 fprintf (stream, "<merge/>\n");
776 fprintf(stderr, "index not -1 but merged\n");
781 fprintf(stderr, "index not -1 but x != 2\n");
784 if (n_categories != 0)
786 fprintf(stderr, "index not -1 but subcategories\n");
789 if (*n_indexes >= *allocated_indexes)
791 *allocated_indexes = *allocated_indexes ? 2 * *allocated_indexes : 16;
792 *indexes = realloc(*indexes, *allocated_indexes * sizeof **indexes);
794 (*indexes)[(*n_indexes)++] = indx;
797 int expected_unindexed = indx == -1;
798 if (unindexed != expected_unindexed)
800 fprintf(stderr, "unindexed (%d) mismatch with indx (%d)\n",
805 if (n_categories == 0)
807 for (int i = 0; i <= level + 1; i++)
808 fprintf (stream, " ");
809 fprintf (stream, "<category-index>%d</category-index>\n", indx);
811 for (int i = 0; i < n_categories; i++)
812 dump_category (stream, level + 1, indexes, allocated_indexes, n_indexes);
813 for (int i = 0; i <= level; i++)
814 fprintf (stream, " ");
815 printf ("</category>\n");
823 printf ("<dimension index=\"%d\">\n", indx);
824 dump_value (stdout, 0);
826 /* This byte is usually 0 but many other values have been spotted. */
829 if (!match_byte(0) && !match_byte(1))
830 match_byte_assert(2);
834 match_byte_assert(1);
836 match_byte_assert(1);
837 match_byte_assert(1);
838 if (!match_u32(UINT32_MAX))
839 match_u32_assert(indx);
840 n_categories = get_u32();
844 int allocated_indexes = 0;
845 for (int i = 0; i < n_categories; i++)
846 dump_category (stdout, 0, &indexes, &allocated_indexes, &n_indexes);
847 check_permutation(indexes, n_indexes, "categories");
849 fprintf (stdout, "</dimension>\n");
854 static int dim_n_cats[64];
855 #define MAX_DIMS (sizeof dim_n_cats / sizeof *dim_n_cats)
861 assert(n_dims < MAX_DIMS);
862 for (int i = 0; i < n_dims; i++)
863 dim_n_cats[i] = dump_dim (i);
869 /* The first three numbers add to the number of dimensions. */
872 int c = n_dims - l - r;
875 /* The next n_dims numbers are a permutation of the dimension numbers. */
877 for (int i = 0; i < n_dims; i++)
882 const char *name = i < l ? "layer" : i < l + r ? "row" : "column";
883 printf ("<%s dimension=\"%d\"/>\n", name, dim);
885 check_permutation(a, n_dims, "dimensions");
889 for (int i = 0; i < x; i++)
891 unsigned int indx = get_u32();
892 printf (" <datum index=\"%d\" coords=", indx);
894 int coords[MAX_DIMS];
895 for (int i = n_dims; i-- > 0; )
897 coords[i] = indx % dim_n_cats[i];
898 indx /= dim_n_cats[i];
900 for (int i = 0; i < n_dims; i++)
901 printf("%c%d", i ? ',' : '"', coords[i]);
907 dump_value(stdout, 1);
908 fprintf (stdout, " </datum>\n");
910 printf ("</data>\n");
916 printf ("<title-local>\n");
917 dump_value(stdout, 0);
919 printf ("</title-local>\n");
921 printf ("<subtype>\n");
922 dump_value(stdout, 0);
924 printf ("</subtype>\n");
926 match_byte_assert(0x31);
928 printf ("<title-c>\n");
929 dump_value(stdout, 0);
931 printf ("</title-c>\n");
933 if (match_byte(0x31))
935 printf ("<user-caption>\n");
936 dump_value(stdout, 0);
937 printf ("</user-caption>\n");
940 match_byte_assert(0x58);
941 if (match_byte(0x31))
943 printf ("<caption>\n");
944 dump_value(stdout, 0);
945 printf ("</caption>\n");
948 match_byte_assert(0x58);
950 int n_footnotes = get_u32();
951 for (int i = 0; i < n_footnotes; i++)
953 printf ("<footnote index=\"%d\">\n", i);
954 dump_value(stdout, 0);
955 /* Custom footnote marker string. */
956 if (match_byte (0x31))
957 dump_value(stdout, 0);
959 match_byte_assert (0x58);
961 printf ("</footnote>\n");
969 for (int i = 1; i <= 8; i++)
971 printf ("<style index=\"%d\"", i);
972 match_byte_assert(i);
973 match_byte_assert(0x31);
974 printf(" font=\"%s\"", get_string());
976 printf(" size=\"%gpt\"", get_float());
978 int style = get_u32();
980 printf(" bold=\"true\"");
982 printf(" italic=\"true\"");
984 bool underline = data[pos++];
986 printf(" underline=\"true\"");
988 int halign = get_u32();
989 printf(" halign=%d", halign);
991 int valign = get_u32();
992 printf(" valign=%d", valign);
994 printf (" fgcolor=\"%s\"", get_string());
995 printf (" bgcolor=\"%s\"", get_string());
998 match_byte_assert(1);
1000 char *alt_fgcolor = get_string();
1002 printf (" altfg=\"%s\"", alt_fgcolor);
1003 char *alt_bgcolor = get_string();
1005 printf (" altbg=\"%s\"", alt_bgcolor);
1009 printf(" margins=\"");
1010 for (int i = 0; i < 4; i++)
1014 printf("%d", get_u32());
1023 int x1_end = pos + x1;
1024 printf("<borders>\n");
1025 match_be32_assert(1);
1026 int n_borders = get_be32();
1027 for (int i = 0; i < n_borders; i++)
1029 int type = get_be32();
1030 int stroke = get_be32();
1031 int color = get_be32();
1032 printf(" <border type=\"%d\" stroke=\"%s\" color=\"#%06x\"/>\n",
1034 (stroke == 0 ? "none"
1035 : stroke == 1 ? "solid"
1036 : stroke == 2 ? "dashed"
1037 : stroke == 3 ? "thick"
1038 : stroke == 4 ? "thin"
1039 : stroke == 5 ? "double"
1043 bool grid = get_byte();
1045 printf(" <grid show=\"%s\"/>\n", grid ? "yes" : "no");
1046 printf("</borders>\n");
1047 assert(pos == x1_end);
1049 int skip = get_u32();
1050 assert(skip == 18 || skip == 25);
1054 int x3_end = pos + x3;
1057 match_be32_assert(1);
1059 printf("<settings layer=\"%d\"", get_be32());
1061 printf(" skipempty=\"false\"");
1063 printf(" showdimensionincorner=\"false\"");
1065 printf(" markers=\"numeric\"");
1067 printf(" footnoteposition=\"subscript\"");
1069 int nbytes = get_be32();
1071 hex_dump(pos, nbytes);
1074 char *notes = get_string_be();
1076 printf(" notes=\"%s\"", notes);
1077 char *look = get_string_be();
1079 printf(" look=\"%s\"", look);
1084 /* Manual column widths, if present. */
1085 int count = get_u32();
1088 printf("<columnwidths>");
1089 for (int i = 0; i < count; i++)
1093 printf("%d", get_u32());
1095 printf("</columnwidths>\n");
1098 const char *locale = get_string();
1099 printf ("<locale>%s</locale>\n", locale);
1101 get_u32(); /* Seen: 0, UINT32_MAX, 2, 3, 4, 5, 6, 8, 9, 21, 24. */
1103 match_byte_assert(1);
1104 match_byte_assert(0);
1106 match_byte_assert(1);
1107 printf("<epoch>%d</epoch>\n", get_u32());
1109 int decimal = data[pos];
1110 int grouping = data[pos + 1];
1111 if (match_byte('.'))
1113 if (!match_byte(',') && !match_byte('\''))
1114 match_byte_assert(' ');
1118 match_byte_assert(',');
1119 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1120 match_byte_assert(0);
1122 printf("<format decimal=\"%c\" grouping=\"", decimal);
1128 for (int i = 0; i < 5; i++)
1129 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1132 match_u32_assert(0);
1134 /* The last chunk is an outer envelope that contains two inner envelopes.
1135 The second inner envelope has some interesting data like the encoding and
1139 int outer_end = get_end();
1141 /* First inner envelope: byte*33 int[n] int*[n]. */
1142 int inner_len = get_u32();
1143 int inner_end = pos + inner_len;
1144 int array_start = pos + 33;
1145 match_byte_assert(0);
1146 pos++; /* 0, 1, 10 seen. */
1147 match_byte_assert(0);
1148 pos++; /* 0...11 seen. */
1149 if (!match_byte(0) && !match_byte(1) && !match_byte(2))
1150 match_byte_assert(3);
1151 if (!match_byte(0) && !match_byte(2))
1152 match_byte_assert(3);
1154 match_u64_assert(UINT64_MAX);
1155 match_u32_assert(0);
1156 match_u32_assert(0);
1157 match_u32_assert(0);
1158 match_u32_assert(0);
1159 match_byte_assert(0);
1161 match_byte_assert(1);
1162 match_byte_assert(1);
1166 while (pos < inner_end)
1167 printf(" %d", get_u32());
1172 /* Second inner envelope. */
1173 assert(get_end() == outer_end);
1175 match_byte_assert(1);
1176 match_byte_assert(0);
1177 if (!match_byte(3) && !match_byte(4))
1178 match_byte_assert(5);
1179 match_byte_assert(0);
1180 match_byte_assert(0);
1181 match_byte_assert(0);
1183 printf("<command>%s</command>\n", get_string());
1184 printf("<subcommand>%s</subcommand>\n", get_string());
1185 printf("<language>%s</language>\n", get_string());
1186 printf("<charset>%s</charset>\n", get_string());
1187 printf("<locale>%s</locale>\n", get_string());
1190 match_byte_assert(1);
1191 match_byte_assert(0);
1193 match_byte_assert(1);
1195 match_byte_assert(1);
1197 printf("<epoch2>%d</epoch2>\n", get_u32());
1199 if (match_byte('.'))
1201 if (!match_byte(',') && !match_byte('\''))
1202 match_byte_assert(' ');
1206 match_byte_assert(',');
1207 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1208 match_byte_assert(0);
1211 printf ("small: %g\n", get_double());
1213 match_byte_assert(1);
1214 if (outer_end - pos > 6)
1216 /* There might be a pair of strings representing a dataset and
1217 datafile name, or there might be a set of custom currency strings.
1218 The custom currency strings start with a pair of integers, so we
1219 can distinguish these from a string by checking for a null byte; a
1220 small 32-bit integer will always contain a null and a text string
1223 int len = get_u32();
1224 bool has_dataset = !memchr(&data[pos], '\0', len);
1229 printf("<dataset>%s</dataset>\n", get_string());
1230 printf("<datafile>%s</datafile>\n", get_string());
1232 match_u32_assert(0);
1234 time_t date = get_u32();
1235 struct tm tm = *localtime(&date);
1237 strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S %z", &tm);
1238 printf("<date>%s</date>\n", s);
1240 match_u32_assert(0);
1246 for (int i = 0; i < 5; i++)
1247 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1250 match_u32_assert(0);
1252 match_byte_assert('.');
1254 match_byte_assert(1);
1256 if (pos < outer_end)
1258 printf("<seed>%d</seed>\n", get_u32());
1259 match_u32_assert(0);
1261 assert(pos == outer_end);
1272 main(int argc, char *argv[])
1277 if (isatty(STDIN_FILENO))
1279 fprintf(stderr, "redirect stdin from a .bin file\n");
1282 if (fstat(STDIN_FILENO, &s))
1294 if (read(STDIN_FILENO, data, n) != n)
1302 fprintf (stderr, "usage: %s TYPE < .bin", argv[0]);
1306 if (!strcmp(argv[1], "title0"))
1309 if (match_byte (0x03)
1310 || (match_byte (0x05) && match_byte (0x58)))
1311 printf ("%s\n", get_string());
1313 printf ("<unknown>\n");
1316 else if (!strcmp(argv[1], "title"))
1322 else if (!strcmp(argv[1], "titleraw"))
1324 const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1326 n = find(fonts, sizeof fonts - 1);
1328 else if (!strcmp(argv[1], "fonts"))
1330 const char fonts[] = "\x01\x31\x09\0\0\0SansSerif";
1331 const char styles[] = "\xf0\0\0\0";
1332 start = find(fonts, sizeof fonts - 1);
1333 n = find(styles, sizeof styles - 1);
1335 else if (!strcmp(argv[1], "styles"))
1337 const char styles[] = "\xf0\0\0\0";
1338 const char dimensions[] = "-,,,.\0";
1339 start = find(styles, sizeof styles - 1);
1340 n = find(dimensions, sizeof dimensions - 1) + sizeof dimensions - 1;
1342 else if (!strcmp(argv[1], "dimensions") || !strcmp(argv[1], "all"))
1345 match_byte_assert(1);
1346 match_byte_assert(0);
1348 /* This might be a version number of some kind, because value 1 seems
1349 to only appear in an SPV file that also required its own weird
1350 special cases in dump_value_modifier(). */
1351 version = get_u32();
1354 match_u32_assert(3);
1356 match_byte_assert(1);
1357 for (int i = 0; i < 4; i++)
1359 match_byte_assert(1);
1362 int min_col_width = get_u32();
1363 int max_col_width = get_u32();
1364 int min_row_width = get_u32();
1365 int max_row_width = get_u32();
1366 printf("<label-width min-col=\"%d\" max-col=\"%d\" min-row=\"%d\" "
1367 "max-row=\"%d\"/>\n",
1368 min_col_width, max_col_width,
1369 min_row_width, max_row_width);
1372 printf("<tableid>%lld</tableid>", get_u64());
1381 fprintf (stderr, "%x / %x\n", pos, n);
1386 else if (!strcmp(argv[1], "raw"))
1390 dump_raw(stdout, start, n);
1394 fprintf (stderr, "unknown section %s\n", argv[1]);