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, " ");
511 printf ("%02x: value (%d)\n", pos, data[pos]);
517 dump_value_modifier(stream);
519 value = get_double ();
520 fprintf (stream, "<number value=\"%.*g\" format=\"%s%d.%d\"/>\n",
521 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
523 else if (match_byte (2))
529 dump_value_modifier (stream);
531 value = get_double ();
533 vallab = get_string ();
534 fprintf (stream, "<numeric-datum value=\"%.*g\" format=\"%s%d.%d\"",
535 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
537 fprintf (stream, " variable=\"%s\"", var);
539 fprintf (stream, " label=\"%s\"", vallab);
540 fprintf (stream, "/>\n");
541 if (!match_byte (1) && !match_byte(2))
542 match_byte_assert (3);
544 else if (match_byte (3))
546 char *text = get_string();
547 dump_value_modifier(stream);
548 char *identifier = get_string();
549 char *text_eng = get_string();
550 fprintf (stream, "<string c=\"%s\"", text_eng);
552 fprintf (stream, " identifier=\"%s\"", identifier);
553 if (strcmp(text_eng, text))
554 fprintf (stream, " local=\"%s\"", text);
555 fprintf (stream, "/>\n");
557 match_byte_assert(1);
559 else if (match_byte (4))
562 char *var, *vallab, *value;
564 dump_value_modifier(stream);
566 vallab = get_string ();
568 if (!match_byte(1) && !match_byte(2))
569 match_byte_assert (3);
570 value = get_string ();
571 fprintf (stream, "<string-datum value=\"%s\" format=\"%s%d.%d\"",
572 value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
574 fprintf (stream, " variable=\"%s\"", var);
576 fprintf (stream, " label=\"%s\"/>\n", vallab);
577 fprintf (stream, "/>\n");
579 else if (match_byte (5))
581 dump_value_modifier(stream);
582 char *name = get_string ();
583 char *label = get_string ();
584 fprintf (stream, "<variable name=\"%s\"", name);
586 fprintf (stream, " label=\"%s\"", label);
587 fprintf (stream, "/>\n");
588 if (!match_byte(1) && !match_byte(2))
589 match_byte_assert(3);
593 printf ("else %#x\n", pos);
594 dump_value_modifier(stream);
596 char *base = get_string();
598 fprintf (stream, "<template format=\"%s\">\n", base);
599 for (int i = 0; i < x; i++)
606 for (int j = 0; j <= level + 1; j++)
607 fprintf (stream, " ");
608 fprintf (stream, "<substitution index=\"%d\">\n", i + 1);
609 for (int j = 0; j < y; j++)
610 dump_value (stream, level + 2);
611 for (int j = 0; j <= level + 1; j++)
612 fprintf (stream, " ");
613 fprintf (stream, "</substitution>\n");
615 for (int j = 0; j <= level; j++)
616 fprintf (stream, " ");
617 fprintf (stream, "</template>\n");
622 compare_int(const void *a_, const void *b_)
626 return *a < *b ? -1 : *a > *b;
630 check_permutation(int *a, int n, const char *name)
633 memcpy(b, a, n * sizeof *a);
634 qsort(b, n, sizeof *b, compare_int);
635 for (int i = 0; i < n; i++)
638 fprintf(stderr, "bad %s permutation:", name);
639 for (int i = 0; i < n; i++)
640 fprintf(stderr, " %d", a[i]);
647 dump_category(FILE *stream, int level, int **indexes, int *allocated_indexes,
650 for (int i = 0; i <= level; i++)
651 fprintf (stream, " ");
652 printf ("<category>\n");
653 dump_value (stream, level + 1);
655 bool merge = get_bool();
656 match_byte_assert (0);
657 int unindexed = get_bool();
662 match_u32_assert (2);
664 int indx = get_u32();
665 int n_categories = get_u32();
670 for (int i = 0; i <= level + 1; i++)
671 fprintf (stream, " ");
672 fprintf (stream, "<merge/>\n");
681 assert (n_categories == 0);
682 if (*n_indexes >= *allocated_indexes)
684 *allocated_indexes = *allocated_indexes ? 2 * *allocated_indexes : 16;
685 *indexes = realloc(*indexes, *allocated_indexes * sizeof **indexes);
687 (*indexes)[(*n_indexes)++] = indx;
690 if (n_categories == 0)
692 for (int i = 0; i <= level + 1; i++)
693 fprintf (stream, " ");
694 fprintf (stream, "<category-index>%d</category-index>\n", indx);
696 for (int i = 0; i < n_categories; i++)
697 dump_category (stream, level + 1, indexes, allocated_indexes, n_indexes);
698 for (int i = 0; i <= level; i++)
699 fprintf (stream, " ");
700 printf ("</category>\n");
708 printf ("<dimension index=\"%d\">\n", indx);
709 dump_value (stdout, 0);
711 /* This byte is usually 0 but many other values have been spotted.
712 No visible effect. */
715 /* This byte can cause data to be oddly replicated. */
716 if (!match_byte(0) && !match_byte(1))
717 match_byte_assert(2);
722 bool show_dim_label = get_bool();
724 printf(" <show-dim-label/>\n");
726 bool hide_all_labels = get_bool();
728 printf(" <hide-all-labels/>\n");
730 match_byte_assert(1);
731 if (!match_u32(UINT32_MAX))
732 match_u32_assert(indx);
734 n_categories = get_u32();
738 int allocated_indexes = 0;
739 for (int i = 0; i < n_categories; i++)
740 dump_category (stdout, 0, &indexes, &allocated_indexes, &n_indexes);
741 check_permutation(indexes, n_indexes, "categories");
743 fprintf (stdout, "</dimension>\n");
748 static int dim_n_cats[64];
749 #define MAX_DIMS (sizeof dim_n_cats / sizeof *dim_n_cats)
755 assert(n_dims < MAX_DIMS);
756 for (int i = 0; i < n_dims; i++)
757 dim_n_cats[i] = dump_dim (i);
763 /* The first three numbers add to the number of dimensions. */
766 int c = n_dims - l - r;
769 /* The next n_dims numbers are a permutation of the dimension numbers. */
771 for (int i = 0; i < n_dims; i++)
776 const char *name = i < l ? "layer" : i < l + r ? "row" : "column";
777 printf ("<%s dimension=\"%d\"/>\n", name, dim);
779 check_permutation(a, n_dims, "dimensions");
783 for (int i = 0; i < x; i++)
785 unsigned int indx = get_u32();
786 printf (" <datum index=\"%d\" coords=", indx);
788 int coords[MAX_DIMS];
789 for (int i = n_dims; i-- > 0; )
791 coords[i] = indx % dim_n_cats[i];
792 indx /= dim_n_cats[i];
794 for (int i = 0; i < n_dims; i++)
795 printf("%c%d", i ? ',' : '"', coords[i]);
801 dump_value(stdout, 1);
802 fprintf (stdout, " </datum>\n");
804 printf ("</data>\n");
810 printf ("<title-local>\n");
811 dump_value(stdout, 0);
813 printf ("</title-local>\n");
815 printf ("<subtype>\n");
816 dump_value(stdout, 0);
818 printf ("</subtype>\n");
820 match_byte_assert(0x31);
822 printf ("<title-c>\n");
823 dump_value(stdout, 0);
825 printf ("</title-c>\n");
827 if (match_byte(0x31))
829 printf ("<user-caption>\n");
830 dump_value(stdout, 0);
831 printf ("</user-caption>\n");
834 match_byte_assert(0x58);
835 if (match_byte(0x31))
837 printf ("<caption>\n");
838 dump_value(stdout, 0);
839 printf ("</caption>\n");
842 match_byte_assert(0x58);
844 int n_footnotes = get_u32();
845 for (int i = 0; i < n_footnotes; i++)
847 printf ("<footnote index=\"%d\">\n", i);
848 dump_value(stdout, 0);
849 /* Custom footnote marker string. */
850 if (match_byte (0x31))
851 dump_value(stdout, 0);
853 match_byte_assert (0x58);
857 /* Appears to be the number of references to a footnote. */
858 printf (" <references n=\"%d\"/>\n", n);
862 /* The user deleted the footnote references. */
863 printf (" <deleted/>\n");
867 printf ("</footnote>\n");
875 for (int i = 1; i <= 8; i++)
877 printf ("<style index=\"%d\"", i);
878 match_byte_assert(i);
879 match_byte_assert(0x31);
880 printf(" font=\"%s\"", get_string());
882 printf(" size=\"%gpt\"", get_float());
884 int style = get_u32();
886 printf(" bold=\"true\"");
888 printf(" italic=\"true\"");
890 bool underline = data[pos++];
892 printf(" underline=\"true\"");
894 int halign = get_u32();
895 printf(" halign=%d", halign);
897 int valign = get_u32();
898 printf(" valign=%d", valign);
900 printf (" fgcolor=\"%s\"", get_string());
901 printf (" bgcolor=\"%s\"", get_string());
904 match_byte_assert(1);
906 char *alt_fgcolor = get_string();
908 printf (" altfg=\"%s\"", alt_fgcolor);
909 char *alt_bgcolor = get_string();
911 printf (" altbg=\"%s\"", alt_bgcolor);
915 printf(" margins=\"");
916 for (int i = 0; i < 4; i++)
920 printf("%d", get_u32());
929 int x1_end = pos + x1;
930 printf("<borders>\n");
931 match_be32_assert(1);
932 int n_borders = get_be32();
933 for (int i = 0; i < n_borders; i++)
935 int type = get_be32();
936 int stroke = get_be32();
937 int color = get_be32();
938 printf(" <border type=\"%d\" stroke=\"%s\" color=\"#%06x\"/>\n",
940 (stroke == 0 ? "none"
941 : stroke == 1 ? "solid"
942 : stroke == 2 ? "dashed"
943 : stroke == 3 ? "thick"
944 : stroke == 4 ? "thin"
945 : stroke == 5 ? "double"
949 bool grid = get_byte();
951 printf(" <grid show=\"%s\"/>\n", grid ? "yes" : "no");
952 printf("</borders>\n");
953 assert(pos == x1_end);
955 int skip = get_u32();
956 assert(skip == 18 || skip == 25);
960 int x3_end = pos + x3;
963 match_be32_assert(1);
965 printf("<settings layer=\"%d\"", get_be32());
967 printf(" skipempty=\"false\"");
969 printf(" showdimensionincorner=\"false\"");
971 printf(" markers=\"numeric\"");
973 printf(" footnoteposition=\"subscript\"");
975 int nbytes = get_be32();
976 int end = pos + nbytes;
978 while (pos + 4 <= end)
979 printf(" %d", get_be32());
983 char *notes = get_string_be();
985 printf(" notes=\"%s\"", notes);
986 char *look = get_string_be();
988 printf(" look=\"%s\"", look);
993 /* Manual column widths, if present. */
994 int count = get_u32();
997 printf("<columnwidths>");
998 for (int i = 0; i < count; i++)
1002 printf("%d", get_u32());
1004 printf("</columnwidths>\n");
1007 const char *locale = get_string();
1008 printf ("<locale>%s</locale>\n", locale);
1010 printf ("<layer>%d</layer>\n", get_u32());
1012 match_byte_assert(1);
1014 match_byte_assert(1);
1016 match_byte_assert(1);
1017 printf("<epoch>%d</epoch>\n", get_u32());
1019 int decimal = data[pos];
1020 int grouping = data[pos + 1];
1021 if (match_byte('.'))
1023 if (!match_byte(',') && !match_byte('\''))
1024 match_byte_assert(' ');
1028 match_byte_assert(',');
1029 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1030 match_byte_assert(0);
1032 printf("<format decimal=\"%c\"", decimal);
1034 printf(" grouping=\"%c\"", grouping);
1038 for (int i = 0; i < 5; i++)
1039 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1042 match_u32_assert(0);
1044 /* The last chunk is an outer envelope that contains two inner envelopes.
1045 The second inner envelope has some interesting data like the encoding and
1047 int outer_end = get_end();
1050 /* First inner envelope: byte*33 int[n] int*[n]. */
1051 int inner_len = get_u32();
1052 int inner_end = pos + inner_len;
1053 int array_start = pos + 33;
1054 match_byte_assert(0);
1055 pos++; /* 0, 1, 10 seen. */
1058 /* 0=en 1=de 2=es 3=it 5=ko 6=pl 8=zh-tw 10=pt_BR 11=fr */
1059 printf("lang=%d ", get_byte());
1061 printf ("variable_mode=%d\n", get_byte());
1062 printf ("value_mode=%d\n", get_byte());
1064 match_u64_assert(UINT64_MAX);
1065 match_u32_assert(0);
1066 match_u32_assert(0);
1067 match_u32_assert(0);
1068 match_u32_assert(0);
1069 match_byte_assert(0);
1071 match_byte_assert(1);
1074 assert(get_end() == inner_end);
1075 printf("<heights>");
1076 int n_heights = get_u32();
1077 for (int i = 0; i < n_heights; i++)
1081 printf("%d", get_u32());
1083 printf("</heights>\n");
1085 int n_style_map = get_u32();
1086 for (int i = 0; i < n_style_map; i++)
1088 uint64_t cell = get_u64();
1089 int style = get_u16();
1090 printf("<style-map cell=\"%llu\" style=\"%d\"/>\n", cell, style);
1093 int n_styles = get_u32();
1094 for (int i = 0; i < n_styles; i++)
1096 printf("<cell-style index=\"%d\"", i);
1098 dump_style2(stdout);
1103 assert(pos == inner_end);
1105 /* Second inner envelope. */
1106 assert(get_end() == outer_end);
1108 match_byte_assert(1);
1109 match_byte_assert(0);
1110 if (!match_byte(3) && !match_byte(4))
1111 match_byte_assert(5);
1112 match_byte_assert(0);
1113 match_byte_assert(0);
1114 match_byte_assert(0);
1116 printf("<command>%s</command>\n", get_string());
1117 printf("<command-local>%s</command-local>\n", get_string());
1118 printf("<language>%s</language>\n", get_string());
1119 printf("<charset>%s</charset>\n", get_string());
1120 printf("<locale>%s</locale>\n", get_string());
1127 printf("<epoch2>%d</epoch2>\n", get_u32());
1129 if (match_byte('.'))
1131 if (!match_byte(',') && !match_byte('\''))
1132 match_byte_assert(' ');
1136 match_byte_assert(',');
1137 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1138 match_byte_assert(0);
1141 printf ("small: %g\n", get_double());
1143 match_byte_assert(1);
1144 if (outer_end - pos > 6)
1146 /* There might be a pair of strings representing a dataset and
1147 datafile name, or there might be a set of custom currency strings.
1148 The custom currency strings start with a pair of integers, so we
1149 can distinguish these from a string by checking for a null byte; a
1150 small 32-bit integer will always contain a null and a text string
1153 int len = get_u32();
1154 bool has_dataset = !memchr(&data[pos], '\0', len);
1159 printf("<dataset>%s</dataset>\n", get_string());
1160 printf("<datafile>%s</datafile>\n", get_string());
1162 match_u32_assert(0);
1164 time_t date = get_u32();
1165 struct tm tm = *localtime(&date);
1167 strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S %z", &tm);
1168 printf("<date>%s</date>\n", s);
1170 match_u32_assert(0);
1176 for (int i = 0; i < 5; i++)
1177 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1180 match_u32_assert(0);
1182 match_byte_assert('.');
1185 if (pos < outer_end)
1188 match_u32_assert(0);
1190 assert(pos == outer_end);
1194 else if (outer_end != pos)
1197 printf("<command>%s</command>\n", get_string());
1198 printf("<command-local>%s</command-local>\n", get_string());
1199 printf("<language>%s</command>\n", get_string());
1200 printf("<charset>%s</charset>\n", get_string());
1201 printf("<locale>%s</locale>\n", get_string());
1203 match_byte_assert(0);
1207 printf("<epoch2>%d</epoch2>\n", get_u32());
1208 int decimal = data[pos];
1209 int grouping = data[pos + 1];
1210 if (match_byte('.'))
1212 if (!match_byte(',') && !match_byte('\''))
1213 match_byte_assert(' ');
1217 match_byte_assert(',');
1218 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1219 match_byte_assert(0);
1221 printf("<format decimal=\"%c\"", decimal);
1223 printf(" grouping=\"%c\"", grouping);
1227 for (int i = 0; i < 5; i++)
1228 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1231 match_u32_assert(0);
1233 match_byte_assert('.');
1236 assert(pos == outer_end);
1242 main(int argc, char *argv[])
1246 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
1251 int fd = open(filename, O_RDONLY);
1254 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
1271 if (read(fd, data, n) != n)
1279 match_byte_assert(1);
1280 match_byte_assert(0);
1282 version = get_u32();
1283 assert(version == 1 || version == 3);
1285 match_byte_assert(1);
1286 bool number_footnotes = get_bool();
1287 printf("<footnote markers=\"%s\"/>\n",
1288 number_footnotes ? "number" : "letter");
1289 bool rotate_inner_column_labels = get_bool();
1290 bool rotate_outer_row_labels = get_bool();
1291 printf("x=%d\n", get_bool());
1292 printf("<rotate-labels inner-column=\"%s\" outer-row=\"%s\"/>",
1293 rotate_inner_column_labels ? "yes" : "no",
1294 rotate_outer_row_labels ? "yes" : "no");
1295 //fprintf(stderr, "option-number=%d\n", get_u32());
1298 int min_col_width = get_u32();
1299 int max_col_width = get_u32();
1300 int min_row_width = get_u32();
1301 int max_row_width = get_u32();
1302 printf("<label-width min-col=\"%d\" max-col=\"%d\" min-row=\"%d\" "
1303 "max-row=\"%d\"/>\n",
1304 min_col_width, max_col_width,
1305 min_row_width, max_row_width);
1308 printf("<tableid>%lld</tableid>", get_u64());
1317 fprintf (stderr, "%x / %x\n", pos, n);