13 #include "u8-mbtouc.h"
15 static const char *filename;
24 #define STR(x) XSTR(x)
25 #define WHERE __FILE__":" STR(__LINE__)
37 memcpy(&x, &data[pos], 4);
42 static unsigned long long int
46 memcpy(&x, &data[pos], 8);
55 x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
64 memcpy(&x, &data[pos], 2);
73 memcpy(&x, &data[pos], 8);
78 static double __attribute__((unused))
82 memcpy(&x, &data[pos], 4);
97 match_u32_assert(uint32_t x, const char *where)
99 unsigned int y = get_u32();
102 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
106 #define match_u32_assert(x) match_u32_assert(x, WHERE)
108 static bool __attribute__((unused))
109 match_u64(uint64_t x)
117 static void __attribute__((unused))
118 match_u64_assert(uint64_t x, const char *where)
120 unsigned long long int y = get_u64();
123 fprintf(stderr, "%s: 0x%x: expected u64:%llu, got u64:%llu\n", where, pos - 8, x, y);
127 #define match_u64_assert(x) match_u64_assert(x, WHERE)
129 static bool __attribute__((unused))
130 match_be32(uint32_t x)
139 match_be32_assert(uint32_t x, const char *where)
141 unsigned int y = get_be32();
144 fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
148 #define match_be32_assert(x) match_be32_assert(x, WHERE)
151 match_byte(uint8_t b)
153 if (pos < n && data[pos] == b)
163 match_byte_assert(uint8_t b, const char *where)
167 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
171 #define match_byte_assert(b) match_byte_assert(b, WHERE)
178 match_byte_assert(1);
182 static bool __attribute__((unused))
183 all_utf8(const char *p_)
185 const uint8_t *p = (const uint8_t *) p_;
186 size_t len = strlen ((char *) p);
187 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
191 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
192 if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
199 get_string(const char *where)
202 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
203 /*&& all_ascii(&data[pos + 4], data[pos])*/)
205 int len = data[pos] + data[pos + 1] * 256;
206 char *s = malloc(len + 1);
208 memcpy(s, &data[pos + 4], len);
215 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
219 #define get_string() get_string(WHERE)
222 get_string_be(const char *where)
225 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
226 /*&& all_ascii(&data[pos + 4], data[pos])*/)
228 int len = data[pos + 2] * 256 + data[pos + 3];
229 char *s = malloc(len + 1);
231 memcpy(s, &data[pos + 4], len);
238 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
242 #define get_string_be() get_string_be(WHERE)
251 static void __attribute__((unused))
252 hex_dump(FILE *stream, int ofs, int n)
254 for (int i = 0; i < n; i++)
256 int c = data[ofs + i];
263 fprintf(stream, "%02x", c);
265 for (int i = 0; i < n; i++)
267 int c = data[ofs + i];
268 putc(c >= 32 && c < 127 ? c : '.', stream);
274 dump_counted_string(void)
276 int inner_end = get_end();
277 if (pos == inner_end)
283 match_byte_assert(0x58);
289 if (match_byte(0x31))
292 match_byte_assert(0x58);
293 if (pos != inner_end)
295 fprintf(stderr, "inner end discrepancy\n");
302 dump_style(FILE *stream)
304 if (match_byte(0x58))
307 match_byte_assert(0x31);
309 printf (" bold=\"yes\"");
311 printf (" italic=\"yes\"");
313 printf (" underline=\"yes\"");
315 printf (" show=\"no\"");
316 char *fg = get_string(); /* foreground */
317 char *bg = get_string(); /* background */
318 char *font = get_string(); /* font */
319 int size = get_byte() * (72. / 96.);
320 fprintf(stream, " fgcolor=\"%s\" bgcolor=\"%s\" font=\"%s\" size=\"%dpt\"",
325 dump_style2(FILE *stream)
327 if (match_byte(0x58))
330 match_byte_assert(0x31);
331 uint32_t halign = get_u32();
332 printf (" halign=\"%s\"",
333 halign == 0 ? "center"
334 : halign == 2 ? "left"
335 : halign == 4 ? "right"
336 : halign == 6 ? "decimal"
337 : halign == 0xffffffad ? "mixed"
339 int valign = get_u32();
340 printf (" valign=\"%s\"",
341 valign == 0 ? "center"
342 : valign == 1 ? "top"
343 : valign == 3 ? "bottom"
345 printf (" offset=\"%gpt\"", get_double());
350 printf (" margins=\"%d %d %d %d\"", l, r, t, b);
354 dump_nested_string(FILE *stream)
358 match_byte_assert (0);
359 match_byte_assert (0);
360 int outer_end = get_end();
361 s = dump_counted_string();
363 fprintf(stream, " \"%s\"", s);
365 match_byte_assert(0x58);
366 if (pos != outer_end)
368 fprintf(stderr, "outer end discrepancy\n");
376 dump_value_modifier(FILE *stream)
378 if (match_byte (0x31))
382 fprintf(stream, "<special0");
385 /* Corpus frequencies:
390 The given text is appended to the cell in a subscript font.
392 fprintf(stream, " subscript=\"%s\"", get_string());
395 match_u32_assert (0);
399 /* We only have one SPV file for this version (with many
406 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))
407 match_u32_assert(10);
410 fprintf(stream, "/>\n");
414 int outer_end = get_end();
416 /* This counted-string appears to be a template string,
417 e.g. "Design\: [:^1:]1 Within Subjects Design\: [:^1:]2". */
418 char *template = dump_counted_string();
420 fprintf(stream, " template=\"%s\"", template);
424 if (pos != outer_end)
426 fprintf(stderr, "outer end discrepancy\n");
429 fprintf(stream, "/>\n");
433 int count = get_u32();
434 fprintf(stream, "<footnote-ref indexes=\"");
435 for (int i = 0; i < count; i++)
439 fprintf(stream, "%d", get_u16());
442 match_byte_assert(0);
443 match_byte_assert(0);
444 dump_nested_string(stream);
445 fprintf(stream, "/>\n");
449 match_byte_assert (0x58);
453 format_to_string (int type)
459 case 2: return "AHEX";
460 case 3: return "COMMA";
461 case 4: return "DOLLAR";
462 case 5: case 40: return "F";
464 case 7: return "PIBHEX";
466 case 9: return "PIB";
467 case 10: return "PK";
468 case 11: return "RB";
469 case 12: return "RBHEX";
473 case 20: return "DATE";
474 case 21: return "TIME";
475 case 22: return "DATETIME";
476 case 23: return "ADATE";
477 case 24: return "JDATE";
478 case 25: return "DTIME";
479 case 26: return "WKDAY";
480 case 27: return "MONTH";
481 case 28: return "MOYR";
482 case 29: return "QYR";
483 case 30: return "WKYR";
484 case 31: return "PCT";
485 case 32: return "DOT";
486 case 33: return "CCA";
487 case 34: return "CCB";
488 case 35: return "CCC";
489 case 36: return "CCD";
490 case 37: return "CCE";
491 case 38: return "EDATE";
492 case 39: return "SDATE";
495 sprintf(tmp, "<%d>", type);
501 dump_value(FILE *stream, int level)
508 for (int i = 0; i <= level; i++)
509 fprintf (stream, " ");
516 dump_value_modifier(stream);
518 value = get_double ();
519 fprintf (stream, "<number value=\"%.*g\" format=\"%s%d.%d\"/>\n",
520 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
522 else if (match_byte (2))
528 dump_value_modifier (stream);
530 value = get_double ();
532 vallab = get_string ();
533 fprintf (stream, "<numeric-datum value=\"%.*g\" format=\"%s%d.%d\"",
534 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
536 fprintf (stream, " variable=\"%s\"", var);
538 fprintf (stream, " label=\"%s\"", vallab);
539 fprintf (stream, "/>\n");
540 if (!match_byte (1) && !match_byte(2))
541 match_byte_assert (3);
543 else if (match_byte (3))
545 char *text = get_string();
546 dump_value_modifier(stream);
547 char *identifier = get_string();
548 char *text_eng = get_string();
549 fprintf (stream, "<string c=\"%s\"", text_eng);
551 fprintf (stream, " identifier=\"%s\"", identifier);
552 if (strcmp(text_eng, text))
553 fprintf (stream, " local=\"%s\"", text);
554 fprintf (stream, "/>\n");
556 match_byte_assert(1);
558 else if (match_byte (4))
561 char *var, *vallab, *value;
563 dump_value_modifier(stream);
565 vallab = get_string ();
567 if (!match_byte(1) && !match_byte(2))
568 match_byte_assert (3);
569 value = get_string ();
570 fprintf (stream, "<string-datum value=\"%s\" format=\"%s%d.%d\"",
571 value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
573 fprintf (stream, " variable=\"%s\"", var);
575 fprintf (stream, " label=\"%s\"/>\n", vallab);
576 fprintf (stream, "/>\n");
578 else if (match_byte (5))
580 dump_value_modifier(stream);
581 char *name = get_string ();
582 char *label = get_string ();
583 fprintf (stream, "<variable name=\"%s\"", name);
585 fprintf (stream, " label=\"%s\"", label);
586 fprintf (stream, "/>\n");
587 if (!match_byte(1) && !match_byte(2))
588 match_byte_assert(3);
592 dump_value_modifier(stream);
594 char *base = get_string();
596 fprintf (stream, "<template format=\"%s\">\n", base);
597 for (int i = 0; i < x; i++)
604 for (int j = 0; j <= level + 1; j++)
605 fprintf (stream, " ");
606 fprintf (stream, "<substitution index=\"%d\">\n", i + 1);
607 for (int j = 0; j < y; j++)
608 dump_value (stream, level + 2);
609 for (int j = 0; j <= level + 1; j++)
610 fprintf (stream, " ");
611 fprintf (stream, "</substitution>\n");
613 for (int j = 0; j <= level; j++)
614 fprintf (stream, " ");
615 fprintf (stream, "</template>\n");
620 compare_int(const void *a_, const void *b_)
624 return *a < *b ? -1 : *a > *b;
628 check_permutation(int *a, int n, const char *name)
631 memcpy(b, a, n * sizeof *a);
632 qsort(b, n, sizeof *b, compare_int);
633 for (int i = 0; i < n; i++)
636 fprintf(stderr, "bad %s permutation:", name);
637 for (int i = 0; i < n; i++)
638 fprintf(stderr, " %d", a[i]);
645 dump_category(FILE *stream, int level, int **indexes, int *allocated_indexes,
648 for (int i = 0; i <= level; i++)
649 fprintf (stream, " ");
650 printf ("<category>\n");
651 dump_value (stream, level + 1);
653 int merge = data[pos];
655 match_byte_assert (1);
657 match_byte_assert (0);
659 int unindexed = data[pos];
661 match_byte_assert (1);
666 match_u32_assert (2);
668 int indx = get_u32();
669 int n_categories = get_u32();
674 for (int i = 0; i <= level + 1; i++)
675 fprintf (stream, " ");
676 fprintf (stream, "<merge/>\n");
683 fprintf(stderr, "index not -1 but merged\n");
688 fprintf(stderr, "index not -1 but x != 2\n");
691 if (n_categories != 0)
693 fprintf(stderr, "index not -1 but subcategories\n");
696 if (*n_indexes >= *allocated_indexes)
698 *allocated_indexes = *allocated_indexes ? 2 * *allocated_indexes : 16;
699 *indexes = realloc(*indexes, *allocated_indexes * sizeof **indexes);
701 (*indexes)[(*n_indexes)++] = indx;
704 int expected_unindexed = indx == -1;
705 if (unindexed != expected_unindexed)
707 fprintf(stderr, "unindexed (%d) mismatch with indx (%d)\n",
712 if (n_categories == 0)
714 for (int i = 0; i <= level + 1; i++)
715 fprintf (stream, " ");
716 fprintf (stream, "<category-index>%d</category-index>\n", indx);
718 for (int i = 0; i < n_categories; i++)
719 dump_category (stream, level + 1, indexes, allocated_indexes, n_indexes);
720 for (int i = 0; i <= level; i++)
721 fprintf (stream, " ");
722 printf ("</category>\n");
730 printf ("<dimension index=\"%d\">\n", indx);
731 dump_value (stdout, 0);
733 /* This byte is usually 0 but many other values have been spotted. */
736 if (!match_byte(0) && !match_byte(1))
737 match_byte_assert(2);
741 match_byte_assert(1);
743 match_byte_assert(1);
744 match_byte_assert(1);
745 if (!match_u32(UINT32_MAX))
746 match_u32_assert(indx);
747 n_categories = get_u32();
751 int allocated_indexes = 0;
752 for (int i = 0; i < n_categories; i++)
753 dump_category (stdout, 0, &indexes, &allocated_indexes, &n_indexes);
754 check_permutation(indexes, n_indexes, "categories");
756 fprintf (stdout, "</dimension>\n");
761 static int dim_n_cats[64];
762 #define MAX_DIMS (sizeof dim_n_cats / sizeof *dim_n_cats)
768 assert(n_dims < MAX_DIMS);
769 for (int i = 0; i < n_dims; i++)
770 dim_n_cats[i] = dump_dim (i);
776 /* The first three numbers add to the number of dimensions. */
779 int c = n_dims - l - r;
782 /* The next n_dims numbers are a permutation of the dimension numbers. */
784 for (int i = 0; i < n_dims; i++)
789 const char *name = i < l ? "layer" : i < l + r ? "row" : "column";
790 printf ("<%s dimension=\"%d\"/>\n", name, dim);
792 check_permutation(a, n_dims, "dimensions");
796 for (int i = 0; i < x; i++)
798 unsigned int indx = get_u32();
799 printf (" <datum index=\"%d\" coords=", indx);
801 int coords[MAX_DIMS];
802 for (int i = n_dims; i-- > 0; )
804 coords[i] = indx % dim_n_cats[i];
805 indx /= dim_n_cats[i];
807 for (int i = 0; i < n_dims; i++)
808 printf("%c%d", i ? ',' : '"', coords[i]);
814 dump_value(stdout, 1);
815 fprintf (stdout, " </datum>\n");
817 printf ("</data>\n");
823 printf ("<title-local>\n");
824 dump_value(stdout, 0);
826 printf ("</title-local>\n");
828 printf ("<subtype>\n");
829 dump_value(stdout, 0);
831 printf ("</subtype>\n");
833 match_byte_assert(0x31);
835 printf ("<title-c>\n");
836 dump_value(stdout, 0);
838 printf ("</title-c>\n");
840 if (match_byte(0x31))
842 printf ("<user-caption>\n");
843 dump_value(stdout, 0);
844 printf ("</user-caption>\n");
847 match_byte_assert(0x58);
848 if (match_byte(0x31))
850 printf ("<caption>\n");
851 dump_value(stdout, 0);
852 printf ("</caption>\n");
855 match_byte_assert(0x58);
857 int n_footnotes = get_u32();
858 for (int i = 0; i < n_footnotes; i++)
860 printf ("<footnote index=\"%d\">\n", i);
861 dump_value(stdout, 0);
862 /* Custom footnote marker string. */
863 if (match_byte (0x31))
864 dump_value(stdout, 0);
866 match_byte_assert (0x58);
870 /* Appears to be the number of references to a footnote. */
871 printf (" <references n=\"%d\"/>\n", n);
875 /* The user deleted the footnote references. */
876 printf (" <deleted/>\n");
880 printf ("</footnote>\n");
888 for (int i = 1; i <= 8; i++)
890 printf ("<style index=\"%d\"", i);
891 match_byte_assert(i);
892 match_byte_assert(0x31);
893 printf(" font=\"%s\"", get_string());
895 printf(" size=\"%gpt\"", get_float());
897 int style = get_u32();
899 printf(" bold=\"true\"");
901 printf(" italic=\"true\"");
903 bool underline = data[pos++];
905 printf(" underline=\"true\"");
907 int halign = get_u32();
908 printf(" halign=%d", halign);
910 int valign = get_u32();
911 printf(" valign=%d", valign);
913 printf (" fgcolor=\"%s\"", get_string());
914 printf (" bgcolor=\"%s\"", get_string());
917 match_byte_assert(1);
919 char *alt_fgcolor = get_string();
921 printf (" altfg=\"%s\"", alt_fgcolor);
922 char *alt_bgcolor = get_string();
924 printf (" altbg=\"%s\"", alt_bgcolor);
928 printf(" margins=\"");
929 for (int i = 0; i < 4; i++)
933 printf("%d", get_u32());
942 int x1_end = pos + x1;
943 printf("<borders>\n");
944 match_be32_assert(1);
945 int n_borders = get_be32();
946 for (int i = 0; i < n_borders; i++)
948 int type = get_be32();
949 int stroke = get_be32();
950 int color = get_be32();
951 printf(" <border type=\"%d\" stroke=\"%s\" color=\"#%06x\"/>\n",
953 (stroke == 0 ? "none"
954 : stroke == 1 ? "solid"
955 : stroke == 2 ? "dashed"
956 : stroke == 3 ? "thick"
957 : stroke == 4 ? "thin"
958 : stroke == 5 ? "double"
962 bool grid = get_byte();
964 printf(" <grid show=\"%s\"/>\n", grid ? "yes" : "no");
965 printf("</borders>\n");
966 assert(pos == x1_end);
968 int skip = get_u32();
969 assert(skip == 18 || skip == 25);
973 int x3_end = pos + x3;
976 match_be32_assert(1);
978 printf("<settings layer=\"%d\"", get_be32());
980 printf(" skipempty=\"false\"");
982 printf(" showdimensionincorner=\"false\"");
984 printf(" markers=\"numeric\"");
986 printf(" footnoteposition=\"subscript\"");
988 int nbytes = get_be32();
989 int end = pos + nbytes;
991 while (pos + 4 <= end)
992 printf(" %d", get_be32());
996 char *notes = get_string_be();
998 printf(" notes=\"%s\"", notes);
999 char *look = get_string_be();
1001 printf(" look=\"%s\"", look);
1006 /* Manual column widths, if present. */
1007 int count = get_u32();
1010 printf("<columnwidths>");
1011 for (int i = 0; i < count; i++)
1015 printf("%d", get_u32());
1017 printf("</columnwidths>\n");
1020 const char *locale = get_string();
1021 printf ("<locale>%s</locale>\n", locale);
1023 printf ("<layer>%d</layer>\n", get_u32());
1025 match_byte_assert(1);
1026 match_byte_assert(0);
1028 match_byte_assert(1);
1029 printf("<epoch>%d</epoch>\n", get_u32());
1031 int decimal = data[pos];
1032 int grouping = data[pos + 1];
1033 if (match_byte('.'))
1035 if (!match_byte(',') && !match_byte('\''))
1036 match_byte_assert(' ');
1040 match_byte_assert(',');
1041 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1042 match_byte_assert(0);
1044 printf("<format decimal=\"%c\"", decimal);
1046 printf(" grouping=\"%c\"", grouping);
1050 for (int i = 0; i < 5; i++)
1051 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1054 match_u32_assert(0);
1056 /* The last chunk is an outer envelope that contains two inner envelopes.
1057 The second inner envelope has some interesting data like the encoding and
1059 int outer_end = get_end();
1062 /* First inner envelope: byte*33 int[n] int*[n]. */
1063 int inner_len = get_u32();
1064 int inner_end = pos + inner_len;
1065 int array_start = pos + 33;
1066 match_byte_assert(0);
1067 pos++; /* 0, 1, 10 seen. */
1070 /* 0=en 1=de 2=es 3=it 5=ko 6=pl 8=zh-tw 10=pt_BR 11=fr */
1071 printf("lang=%d ", get_byte());
1073 printf ("variable_mode=%d\n", get_byte());
1074 printf ("value_mode=%d\n", get_byte());
1076 match_u64_assert(UINT64_MAX);
1077 match_u32_assert(0);
1078 match_u32_assert(0);
1079 match_u32_assert(0);
1080 match_u32_assert(0);
1081 match_byte_assert(0);
1083 match_byte_assert(1);
1086 assert(get_end() == inner_end);
1087 printf("<heights>");
1088 int n_heights = get_u32();
1089 for (int i = 0; i < n_heights; i++)
1093 printf("%d", get_u32());
1095 printf("</heights>\n");
1097 int n_style_map = get_u32();
1098 for (int i = 0; i < n_style_map; i++)
1100 uint64_t cell = get_u64();
1101 int style = get_u16();
1102 printf("<style-map cell=\"%llu\" style=\"%d\"/>\n", cell, style);
1105 int n_styles = get_u32();
1106 for (int i = 0; i < n_styles; i++)
1108 printf("<cell-style index=\"%d\"", i);
1110 dump_style2(stdout);
1115 assert(pos == inner_end);
1117 /* Second inner envelope. */
1118 assert(get_end() == outer_end);
1120 match_byte_assert(1);
1121 match_byte_assert(0);
1122 if (!match_byte(3) && !match_byte(4))
1123 match_byte_assert(5);
1124 match_byte_assert(0);
1125 match_byte_assert(0);
1126 match_byte_assert(0);
1128 printf("<command>%s</command>\n", get_string());
1129 printf("<command-local>%s</command-local>\n", get_string());
1130 printf("<language>%s</language>\n", get_string());
1131 printf("<charset>%s</charset>\n", get_string());
1132 printf("<locale>%s</locale>\n", get_string());
1135 match_byte_assert(0);
1139 printf("<epoch2>%d</epoch2>\n", get_u32());
1141 if (match_byte('.'))
1143 if (!match_byte(',') && !match_byte('\''))
1144 match_byte_assert(' ');
1148 match_byte_assert(',');
1149 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1150 match_byte_assert(0);
1153 printf ("small: %g\n", get_double());
1155 match_byte_assert(1);
1156 if (outer_end - pos > 6)
1158 /* There might be a pair of strings representing a dataset and
1159 datafile name, or there might be a set of custom currency strings.
1160 The custom currency strings start with a pair of integers, so we
1161 can distinguish these from a string by checking for a null byte; a
1162 small 32-bit integer will always contain a null and a text string
1165 int len = get_u32();
1166 bool has_dataset = !memchr(&data[pos], '\0', len);
1171 printf("<dataset>%s</dataset>\n", get_string());
1172 printf("<datafile>%s</datafile>\n", get_string());
1174 match_u32_assert(0);
1176 time_t date = get_u32();
1177 struct tm tm = *localtime(&date);
1179 strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S %z", &tm);
1180 printf("<date>%s</date>\n", s);
1182 match_u32_assert(0);
1188 for (int i = 0; i < 5; i++)
1189 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1192 match_u32_assert(0);
1194 match_byte_assert('.');
1197 if (pos < outer_end)
1200 match_u32_assert(0);
1202 assert(pos == outer_end);
1206 else if (outer_end != pos)
1209 printf("<command>%s</command>\n", get_string());
1210 printf("<command-local>%s</command-local>\n", get_string());
1211 printf("<language>%s</command>\n", get_string());
1212 printf("<charset>%s</charset>\n", get_string());
1213 printf("<locale>%s</locale>\n", get_string());
1215 match_byte_assert(0);
1219 printf("<epoch2>%d</epoch2>\n", get_u32());
1220 int decimal = data[pos];
1221 int grouping = data[pos + 1];
1222 if (match_byte('.'))
1224 if (!match_byte(',') && !match_byte('\''))
1225 match_byte_assert(' ');
1229 match_byte_assert(',');
1230 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1231 match_byte_assert(0);
1233 printf("<format decimal=\"%c\"", decimal);
1235 printf(" grouping=\"%c\"", grouping);
1239 for (int i = 0; i < 5; i++)
1240 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1243 match_u32_assert(0);
1245 match_byte_assert('.');
1248 assert(pos == outer_end);
1254 main(int argc, char *argv[])
1258 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
1263 int fd = open(filename, O_RDONLY);
1266 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
1283 if (read(fd, data, n) != n)
1291 match_byte_assert(1);
1292 match_byte_assert(0);
1294 version = get_u32();
1295 assert(version == 1 || version == 3);
1297 match_byte_assert(1);
1298 bool number_footnotes = get_bool();
1299 printf("<footnote markers=\"%s\"/>\n",
1300 number_footnotes ? "number" : "letter");
1301 bool rotate_inner_column_labels = get_bool();
1302 bool rotate_outer_row_labels = get_bool();
1303 printf("x=%d\n", get_bool());
1304 printf("<rotate-labels inner-column=\"%s\" outer-row=\"%s\"/>",
1305 rotate_inner_column_labels ? "yes" : "no",
1306 rotate_outer_row_labels ? "yes" : "no");
1307 //fprintf(stderr, "option-number=%d\n", get_u32());
1310 int min_col_width = get_u32();
1311 int max_col_width = get_u32();
1312 int min_row_width = get_u32();
1313 int max_row_width = get_u32();
1314 printf("<label-width min-col=\"%d\" max-col=\"%d\" min-row=\"%d\" "
1315 "max-row=\"%d\"/>\n",
1316 min_col_width, max_col_width,
1317 min_row_width, max_row_width);
1320 printf("<tableid>%lld</tableid>", get_u64());
1329 fprintf (stderr, "%x / %x\n", pos, n);