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:%lu, 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)
174 match_bytes(int start, const int *bytes, size_t n_bytes)
176 for (size_t i = 0; i < n_bytes; i++)
177 if (bytes[i] >= 0 && data[start + i] != bytes[i])
187 match_byte_assert(1);
191 static bool __attribute__((unused))
194 return (p >= ' ' && p < 127) || p == '\r' || p == '\n' || p == '\t';
197 static bool __attribute__((unused))
198 all_utf8(const char *p_, size_t len)
200 const uint8_t *p = (const uint8_t *) p_;
201 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
205 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
206 if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
213 get_string(const char *where)
216 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
217 /*&& all_ascii(&data[pos + 4], data[pos])*/)
219 int len = data[pos] + data[pos + 1] * 256;
220 char *s = malloc(len + 1);
222 memcpy(s, &data[pos + 4], len);
229 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
233 #define get_string() get_string(WHERE)
236 get_string_be(const char *where)
239 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
240 /*&& all_ascii(&data[pos + 4], data[pos])*/)
242 int len = data[pos + 2] * 256 + data[pos + 3];
243 char *s = malloc(len + 1);
245 memcpy(s, &data[pos + 4], len);
252 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
256 #define get_string_be() get_string_be(WHERE)
265 static void __attribute__((unused))
266 hex_dump(FILE *stream, int ofs, int n)
268 for (int i = 0; i < n; i++)
270 int c = data[ofs + i];
271 fprintf(stream, " %02x", c);
274 for (int i = 0; i < n; i++)
276 int c = data[ofs + i];
277 putc(c >= 32 && c < 127 ? c : '.', stream);
282 static void __attribute__((unused))
283 char_dump(FILE *stream, int ofs, int n)
285 for (int i = 0; i < n; i++)
287 int c = data[ofs + i];
288 putc(c >= 32 && c < 127 ? c : '.', stream);
294 dump_counted_string(void)
296 int inner_end = get_end();
297 if (pos == inner_end)
303 match_byte_assert(0x58);
309 if (match_byte(0x31))
312 match_byte_assert(0x58);
313 if (pos != inner_end)
315 fprintf(stderr, "inner end discrepancy\n");
322 dump_style(FILE *stream)
324 if (match_byte(0x58))
327 match_byte_assert(0x31);
329 printf (" bold=\"yes\"");
331 printf (" italic=\"yes\"");
333 printf (" underline=\"yes\"");
335 printf (" show=\"no\"");
336 char *fg = get_string(); /* foreground */
337 char *bg = get_string(); /* background */
338 char *font = get_string(); /* font */
339 int size = get_byte() * (72. / 96.);
340 fprintf(stream, " fgcolor=\"%s\" bgcolor=\"%s\" font=\"%s\" size=\"%dpt\"",
345 dump_style2(FILE *stream)
347 if (match_byte(0x58))
350 match_byte_assert(0x31);
351 uint32_t halign = get_u32();
352 printf (" halign=\"%s\"",
353 halign == 0 ? "center"
354 : halign == 2 ? "left"
355 : halign == 4 ? "right"
356 : halign == 6 ? "decimal"
357 : halign == 0xffffffad ? "mixed"
359 int valign = get_u32();
360 printf (" valign=\"%s\"",
361 valign == 0 ? "center"
362 : valign == 1 ? "top"
363 : valign == 3 ? "bottom"
365 printf (" offset=\"%gpt\"", get_double());
370 printf (" margins=\"%d %d %d %d\"", l, r, t, b);
374 dump_nested_string(FILE *stream)
378 match_byte_assert (0);
379 match_byte_assert (0);
380 int outer_end = get_end();
381 s = dump_counted_string();
383 fprintf(stream, " \"%s\"", s);
385 match_byte_assert(0x58);
386 if (pos != outer_end)
388 fprintf(stderr, "outer end discrepancy\n");
396 dump_value_modifier(FILE *stream)
398 if (match_byte (0x31))
402 fprintf(stream, "<special0");
405 /* Corpus frequencies:
410 The given text is appended to the cell in a subscript font.
412 fprintf(stream, " subscript=\"%s\"", get_string());
415 match_u32_assert (0);
419 /* We only have one SPV file for this version (with many
426 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))
427 match_u32_assert(10);
430 fprintf(stream, "/>\n");
434 int outer_end = get_end();
436 /* This counted-string appears to be a template string,
437 e.g. "Design\: [:^1:]1 Within Subjects Design\: [:^1:]2". */
438 char *template = dump_counted_string();
440 fprintf(stream, " template=\"%s\"", template);
444 if (pos != outer_end)
446 fprintf(stderr, "outer end discrepancy\n");
449 fprintf(stream, "/>\n");
453 int count = get_u32();
454 fprintf(stream, "<footnote-ref indexes=\"");
455 for (int i = 0; i < count; i++)
459 fprintf(stream, "%d", get_u16());
462 match_byte_assert(0);
463 match_byte_assert(0);
464 dump_nested_string(stream);
465 fprintf(stream, "/>\n");
469 match_byte_assert (0x58);
473 format_to_string (int type)
479 case 2: return "AHEX";
480 case 3: return "COMMA";
481 case 4: return "DOLLAR";
482 case 5: case 40: return "F";
484 case 7: return "PIBHEX";
486 case 9: return "PIB";
487 case 10: return "PK";
488 case 11: return "RB";
489 case 12: return "RBHEX";
493 case 20: return "DATE";
494 case 21: return "TIME";
495 case 22: return "DATETIME";
496 case 23: return "ADATE";
497 case 24: return "JDATE";
498 case 25: return "DTIME";
499 case 26: return "WKDAY";
500 case 27: return "MONTH";
501 case 28: return "MOYR";
502 case 29: return "QYR";
503 case 30: return "WKYR";
504 case 31: return "PCT";
505 case 32: return "DOT";
506 case 33: return "CCA";
507 case 34: return "CCB";
508 case 35: return "CCC";
509 case 36: return "CCD";
510 case 37: return "CCE";
511 case 38: return "EDATE";
512 case 39: return "SDATE";
515 sprintf(tmp, "<%d>", type);
521 dump_value(FILE *stream, int level)
528 for (int i = 0; i <= level; i++)
529 fprintf (stream, " ");
531 printf ("%02x: value (%d)\n", pos, data[pos]);
537 dump_value_modifier(stream);
539 value = get_double ();
540 fprintf (stream, "<number value=\"%.*g\" format=\"%s%d.%d\"/>\n",
541 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
543 else if (match_byte (2))
549 dump_value_modifier (stream);
551 value = get_double ();
553 vallab = get_string ();
554 fprintf (stream, "<numeric-datum value=\"%.*g\" format=\"%s%d.%d\"",
555 DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
557 fprintf (stream, " variable=\"%s\"", var);
559 fprintf (stream, " label=\"%s\"", vallab);
560 fprintf (stream, "/>\n");
561 if (!match_byte (1) && !match_byte(2))
562 match_byte_assert (3);
564 else if (match_byte (3))
566 char *text = get_string();
567 dump_value_modifier(stream);
568 char *identifier = get_string();
569 char *text_eng = get_string();
570 fprintf (stream, "<string c=\"%s\"", text_eng);
572 fprintf (stream, " identifier=\"%s\"", identifier);
573 if (strcmp(text_eng, text))
574 fprintf (stream, " local=\"%s\"", text);
575 fprintf (stream, "/>\n");
577 match_byte_assert(1);
579 else if (match_byte (4))
582 char *var, *vallab, *value;
584 dump_value_modifier(stream);
586 vallab = get_string ();
588 if (!match_byte(1) && !match_byte(2))
589 match_byte_assert (3);
590 value = get_string ();
591 fprintf (stream, "<string-datum value=\"%s\" format=\"%s%d.%d\"",
592 value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
594 fprintf (stream, " variable=\"%s\"", var);
596 fprintf (stream, " label=\"%s\"/>\n", vallab);
597 fprintf (stream, "/>\n");
599 else if (match_byte (5))
601 dump_value_modifier(stream);
602 char *name = get_string ();
603 char *label = get_string ();
604 fprintf (stream, "<variable name=\"%s\"", name);
606 fprintf (stream, " label=\"%s\"", label);
607 fprintf (stream, "/>\n");
608 if (!match_byte(1) && !match_byte(2))
609 match_byte_assert(3);
613 printf ("else %#x\n", pos);
614 dump_value_modifier(stream);
616 char *base = get_string();
618 fprintf (stream, "<template format=\"%s\">\n", base);
619 for (int i = 0; i < x; i++)
626 for (int j = 0; j <= level + 1; j++)
627 fprintf (stream, " ");
628 fprintf (stream, "<substitution index=\"%d\">\n", i + 1);
629 for (int j = 0; j < y; j++)
630 dump_value (stream, level + 2);
631 for (int j = 0; j <= level + 1; j++)
632 fprintf (stream, " ");
633 fprintf (stream, "</substitution>\n");
635 for (int j = 0; j <= level; j++)
636 fprintf (stream, " ");
637 fprintf (stream, "</template>\n");
642 compare_int(const void *a_, const void *b_)
646 return *a < *b ? -1 : *a > *b;
650 check_permutation(int *a, int n, const char *name)
653 memcpy(b, a, n * sizeof *a);
654 qsort(b, n, sizeof *b, compare_int);
655 for (int i = 0; i < n; i++)
658 fprintf(stderr, "bad %s permutation:", name);
659 for (int i = 0; i < n; i++)
660 fprintf(stderr, " %d", a[i]);
667 dump_category(FILE *stream, int level, int **indexes, int *allocated_indexes,
670 for (int i = 0; i <= level; i++)
671 fprintf (stream, " ");
672 printf ("<category>\n");
673 dump_value (stream, level + 1);
675 bool merge = get_bool();
676 match_byte_assert (0);
677 int unindexed = get_bool();
682 match_u32_assert (2);
684 int indx = get_u32();
685 int n_categories = get_u32();
690 for (int i = 0; i <= level + 1; i++)
691 fprintf (stream, " ");
692 fprintf (stream, "<merge/>\n");
701 assert (n_categories == 0);
702 if (*n_indexes >= *allocated_indexes)
704 *allocated_indexes = *allocated_indexes ? 2 * *allocated_indexes : 16;
705 *indexes = realloc(*indexes, *allocated_indexes * sizeof **indexes);
707 (*indexes)[(*n_indexes)++] = indx;
710 if (n_categories == 0)
712 for (int i = 0; i <= level + 1; i++)
713 fprintf (stream, " ");
714 fprintf (stream, "<category-index>%d</category-index>\n", indx);
716 for (int i = 0; i < n_categories; i++)
717 dump_category (stream, level + 1, indexes, allocated_indexes, n_indexes);
718 for (int i = 0; i <= level; i++)
719 fprintf (stream, " ");
720 printf ("</category>\n");
728 printf ("<dimension index=\"%d\">\n", indx);
729 dump_value (stdout, 0);
731 /* This byte is usually 0 but many other values have been spotted.
732 No visible effect. */
735 /* This byte can cause data to be oddly replicated. */
736 if (!match_byte(0) && !match_byte(1))
737 match_byte_assert(2);
742 bool show_dim_label = get_bool();
744 printf(" <show-dim-label/>\n");
746 bool hide_all_labels = get_bool();
748 printf(" <hide-all-labels/>\n");
750 match_byte_assert(1);
751 if (!match_u32(UINT32_MAX))
752 match_u32_assert(indx);
754 n_categories = get_u32();
758 int allocated_indexes = 0;
759 for (int i = 0; i < n_categories; i++)
760 dump_category (stdout, 0, &indexes, &allocated_indexes, &n_indexes);
761 check_permutation(indexes, n_indexes, "categories");
763 fprintf (stdout, "</dimension>\n");
768 static int dim_n_cats[64];
769 #define MAX_DIMS (sizeof dim_n_cats / sizeof *dim_n_cats)
775 assert(n_dims < MAX_DIMS);
776 for (int i = 0; i < n_dims; i++)
777 dim_n_cats[i] = dump_dim (i);
783 /* The first three numbers add to the number of dimensions. */
786 int c = n_dims - l - r;
789 /* The next n_dims numbers are a permutation of the dimension numbers. */
791 for (int i = 0; i < n_dims; i++)
796 const char *name = i < l ? "layer" : i < l + r ? "row" : "column";
797 printf ("<%s dimension=\"%d\"/>\n", name, dim);
799 check_permutation(a, n_dims, "dimensions");
803 for (int i = 0; i < x; i++)
805 unsigned int indx = get_u32();
806 printf (" <datum index=\"%d\" coords=", indx);
808 int coords[MAX_DIMS];
809 for (int i = n_dims; i-- > 0; )
811 coords[i] = indx % dim_n_cats[i];
812 indx /= dim_n_cats[i];
814 for (int i = 0; i < n_dims; i++)
815 printf("%c%d", i ? ',' : '"', coords[i]);
821 dump_value(stdout, 1);
822 fprintf (stdout, " </datum>\n");
824 printf ("</data>\n");
830 printf ("<title-local>\n");
831 dump_value(stdout, 0);
833 printf ("</title-local>\n");
835 printf ("<subtype>\n");
836 dump_value(stdout, 0);
838 printf ("</subtype>\n");
840 match_byte_assert(0x31);
842 printf ("<title-c>\n");
843 dump_value(stdout, 0);
845 printf ("</title-c>\n");
847 if (match_byte(0x31))
849 printf ("<user-caption>\n");
850 dump_value(stdout, 0);
851 printf ("</user-caption>\n");
854 match_byte_assert(0x58);
855 if (match_byte(0x31))
857 printf ("<caption>\n");
858 dump_value(stdout, 0);
859 printf ("</caption>\n");
862 match_byte_assert(0x58);
864 int n_footnotes = get_u32();
865 for (int i = 0; i < n_footnotes; i++)
867 printf ("<footnote index=\"%d\">\n", i);
868 dump_value(stdout, 0);
869 /* Custom footnote marker string. */
870 if (match_byte (0x31))
871 dump_value(stdout, 0);
873 match_byte_assert (0x58);
877 /* Appears to be the number of references to a footnote. */
878 printf (" <references n=\"%d\"/>\n", n);
882 /* The user deleted the footnote references. */
883 printf (" <deleted/>\n");
887 printf ("</footnote>\n");
895 for (int i = 1; i <= 8; i++)
897 printf ("<style index=\"%d\"", i);
898 match_byte_assert(i);
899 match_byte_assert(0x31);
900 printf(" font=\"%s\"", get_string());
902 printf(" size=\"%gpt\"", get_float());
904 int style = get_u32();
906 printf(" bold=\"true\"");
908 printf(" italic=\"true\"");
910 bool underline = data[pos++];
912 printf(" underline=\"true\"");
914 int halign = get_u32();
915 printf(" halign=%d", halign);
917 int valign = get_u32();
918 printf(" valign=%d", valign);
920 printf (" fgcolor=\"%s\"", get_string());
921 printf (" bgcolor=\"%s\"", get_string());
924 match_byte_assert(1);
926 char *alt_fgcolor = get_string();
928 printf (" altfg=\"%s\"", alt_fgcolor);
929 char *alt_bgcolor = get_string();
931 printf (" altbg=\"%s\"", alt_bgcolor);
935 printf(" margins=\"");
936 for (int i = 0; i < 4; i++)
940 printf("%d", get_u32());
949 int x1_end = pos + x1;
950 printf("<borders>\n");
951 match_be32_assert(1);
952 int n_borders = get_be32();
953 for (int i = 0; i < n_borders; i++)
955 int type = get_be32();
956 int stroke = get_be32();
957 int color = get_be32();
958 printf(" <border type=\"%d\" stroke=\"%s\" color=\"#%06x\"/>\n",
960 (stroke == 0 ? "none"
961 : stroke == 1 ? "solid"
962 : stroke == 2 ? "dashed"
963 : stroke == 3 ? "thick"
964 : stroke == 4 ? "thin"
965 : stroke == 5 ? "double"
969 bool grid = get_byte();
971 printf(" <grid show=\"%s\"/>\n", grid ? "yes" : "no");
972 printf("</borders>\n");
973 assert(pos == x1_end);
975 int skip = get_u32();
976 assert(skip == 18 || skip == 25);
980 int x3_end = pos + x3;
983 match_be32_assert(1);
985 printf("<settings layer=\"%d\"", get_be32());
987 printf(" skipempty=\"false\"");
989 printf(" showdimensionincorner=\"false\"");
991 printf(" markers=\"numeric\"");
993 printf(" footnoteposition=\"subscript\"");
995 int nbytes = get_be32();
996 int end = pos + nbytes;
998 while (pos + 4 <= end)
999 printf(" %d", get_be32());
1003 char *notes = get_string_be();
1005 printf(" notes=\"%s\"", notes);
1006 char *look = get_string_be();
1008 printf(" look=\"%s\"", look);
1013 /* Manual column widths, if present. */
1014 int count = get_u32();
1017 printf("<columnwidths>");
1018 for (int i = 0; i < count; i++)
1022 printf("%d", get_u32());
1024 printf("</columnwidths>\n");
1027 const char *locale = get_string();
1028 printf ("<locale>%s</locale>\n", locale);
1030 printf ("<layer>%d</layer>\n", get_u32());
1032 match_byte_assert(1);
1034 match_byte_assert(1);
1036 match_byte_assert(1);
1037 printf("<epoch>%d</epoch>\n", get_u32());
1039 int decimal = data[pos];
1040 int grouping = data[pos + 1];
1041 if (match_byte('.'))
1043 if (!match_byte(',') && !match_byte('\''))
1044 match_byte_assert(' ');
1048 match_byte_assert(',');
1049 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1050 match_byte_assert(0);
1052 printf("<format decimal=\"%c\"", decimal);
1054 printf(" grouping=\"%c\"", grouping);
1058 for (int i = 0; i < 5; i++)
1059 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1062 match_u32_assert(0);
1064 /* The last chunk is an outer envelope that contains two inner envelopes.
1065 The second inner envelope has some interesting data like the encoding and
1067 int outer_end = get_end();
1070 /* First inner envelope: byte*33 int[n] int*[n]. */
1071 int inner_len = get_u32();
1072 int inner_end = pos + inner_len;
1073 int array_start = pos + 33;
1074 match_byte_assert(0);
1075 pos++; /* 0, 1, 10 seen. */
1078 /* 0=en 1=de 2=es 3=it 5=ko 6=pl 8=zh-tw 10=pt_BR 11=fr */
1079 printf("lang=%d ", get_byte());
1081 printf ("variable_mode=%d\n", get_byte());
1082 printf ("value_mode=%d\n", get_byte());
1084 match_u64_assert(UINT64_MAX);
1085 match_u32_assert(0);
1086 match_u32_assert(0);
1087 match_u32_assert(0);
1088 match_u32_assert(0);
1089 match_byte_assert(0);
1091 match_byte_assert(1);
1094 assert(get_end() == inner_end);
1095 printf("<heights>");
1096 int n_heights = get_u32();
1097 for (int i = 0; i < n_heights; i++)
1101 printf("%d", get_u32());
1103 printf("</heights>\n");
1105 int n_style_map = get_u32();
1106 for (int i = 0; i < n_style_map; i++)
1108 uint64_t cell = get_u64();
1109 int style = get_u16();
1110 printf("<style-map cell=\"%lu\" style=\"%d\"/>\n", cell, style);
1113 int n_styles = get_u32();
1114 for (int i = 0; i < n_styles; i++)
1116 printf("<cell-style index=\"%d\"", i);
1118 dump_style2(stdout);
1123 assert(pos == inner_end);
1125 /* Second inner envelope. */
1126 assert(get_end() == outer_end);
1128 match_byte_assert(1);
1129 match_byte_assert(0);
1130 if (!match_byte(3) && !match_byte(4))
1131 match_byte_assert(5);
1132 match_byte_assert(0);
1133 match_byte_assert(0);
1134 match_byte_assert(0);
1136 printf("<command>%s</command>\n", get_string());
1137 printf("<command-local>%s</command-local>\n", get_string());
1138 printf("<language>%s</language>\n", get_string());
1139 printf("<charset>%s</charset>\n", get_string());
1140 printf("<locale>%s</locale>\n", get_string());
1147 printf("<epoch2>%d</epoch2>\n", get_u32());
1149 if (match_byte('.'))
1151 if (!match_byte(',') && !match_byte('\''))
1152 match_byte_assert(' ');
1156 match_byte_assert(',');
1157 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1158 match_byte_assert(0);
1161 printf ("small: %g\n", get_double());
1163 match_byte_assert(1);
1164 if (outer_end - pos > 6)
1166 /* There might be a pair of strings representing a dataset and
1167 datafile name, or there might be a set of custom currency strings.
1168 The custom currency strings start with a pair of integers, so we
1169 can distinguish these from a string by checking for a null byte; a
1170 small 32-bit integer will always contain a null and a text string
1173 int len = get_u32();
1174 bool has_dataset = !memchr(&data[pos], '\0', len);
1179 printf("<dataset>%s</dataset>\n", get_string());
1180 printf("<datafile>%s</datafile>\n", get_string());
1182 match_u32_assert(0);
1184 time_t date = get_u32();
1185 struct tm tm = *localtime(&date);
1187 strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S %z", &tm);
1188 printf("<date>%s</date>\n", s);
1190 match_u32_assert(0);
1196 for (int i = 0; i < 5; i++)
1197 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1200 match_u32_assert(0);
1202 match_byte_assert('.');
1205 if (pos < outer_end)
1208 match_u32_assert(0);
1210 assert(pos == outer_end);
1214 else if (outer_end != pos)
1217 printf("<command>%s</command>\n", get_string());
1218 printf("<command-local>%s</command-local>\n", get_string());
1219 printf("<language>%s</command>\n", get_string());
1220 printf("<charset>%s</charset>\n", get_string());
1221 printf("<locale>%s</locale>\n", get_string());
1223 match_byte_assert(0);
1227 printf("<epoch2>%d</epoch2>\n", get_u32());
1228 int decimal = data[pos];
1229 int grouping = data[pos + 1];
1230 if (match_byte('.'))
1232 if (!match_byte(',') && !match_byte('\''))
1233 match_byte_assert(' ');
1237 match_byte_assert(',');
1238 if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
1239 match_byte_assert(0);
1241 printf("<format decimal=\"%c\"", decimal);
1243 printf(" grouping=\"%c\"", grouping);
1247 for (int i = 0; i < 5; i++)
1248 printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
1251 match_u32_assert(0);
1253 match_byte_assert('.');
1256 assert(pos == outer_end);
1262 main(int argc, char *argv[])
1266 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
1271 int fd = open(filename, O_RDONLY);
1274 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
1291 if (read(fd, data, n) != n)
1299 unsigned int prev_end = 0;
1300 for (pos = 0; pos + 50 < n; pos++)
1302 if (data[pos + 0] == 0xff &&
1303 data[pos + 1] == 0xff &&
1304 data[pos + 2] == 0 &&
1307 int len = data[pos + 4] + (data[pos + 5] << 8);
1308 if (len < 3 || pos + len + 6 >= n || !all_utf8 ((char *) &data[pos + 6], len))
1311 printf ("+%04x %04x...%04x: %-25.*s\n",
1312 pos - prev_end, pos, pos + 6 + len,
1313 len < 50 ? (int) len : 50, &data[pos + 6]);
1314 prev_end = pos + 6 + len;
1319 for (pos = 0; pos + 50 < n; pos++)
1321 if (data[pos + 0] == 'L' &&
1322 data[pos + 1] == 'o' &&
1323 data[pos + 2] == 'g' &&
1324 !all_utf8((char *) &data[pos + 3], 1) &&
1325 data[pos - 1] != 'v')
1327 //printf ("%04x: ", pos);
1328 unsigned int p = pos;
1329 while (all_utf8 ((char *) &data[p], 1))
1331 hex_dump (stdout, p - 28, 38);
1335 unsigned int prev_end = 0;
1336 for (pos = 2; pos + 50 < n; pos++)
1338 static const int cell_prefix[] = {
1339 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
1340 0x00, 0x00, 0x00, 0x00, 0x00, -1, 0x80, 0x01, -1, -1,
1341 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1343 size_t cell_prefix_len = sizeof cell_prefix / sizeof *cell_prefix;
1344 if (match_bytes(pos, cell_prefix, cell_prefix_len))
1346 if (prev_end != pos)
1348 printf ("%04x ", prev_end);
1349 hex_dump (stdout, prev_end, pos - prev_end);
1352 printf ("cell %04x %d %d %d %d %d %d ", pos,
1353 data[pos + 13], data[pos + 16], data[pos + 17],
1354 data[pos + 18], data[pos + 19], data[pos + 20]);
1356 int len = cell_prefix_len;
1357 if (data[pos + 19] == 0)
1359 if (data[pos + 20] == 0)
1361 int count = (data[pos + 22]);
1362 printf ("/ %d %d %d \"%.*s\"\n",
1363 data[pos + 20], data[pos + 21], data[pos + 22],
1364 count, &data[pos + 23]);
1367 else if (data[pos + 20] == 1
1368 && data[pos + 21] == 0xff
1369 && data[pos + 22] == 0xff)
1372 printf ("/ \"%.*s\"\n", count, &data[pos + 24]);
1375 else if (data[pos + 20] == 1 )
1377 int count = (data[pos + 21]);
1378 printf ("/ %d %d %d \"%.*s\"\n",
1379 data[pos + 20], data[pos + 21], data[pos + 22],
1380 count, &data[pos + 22]);
1386 else if (data[pos + 19] == 128)
1388 double d = *(double *) &data[pos + cell_prefix_len - 8];
1394 sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
1396 printf ("sysmis\n");
1407 static const int col_prefix[] = {
1408 0x11, 0x80, 0x00, -1, 0x00, 0x00, 0x00, 0x01, 0x00
1410 size_t col_prefix_len = sizeof col_prefix / sizeof *col_prefix;
1411 if (match_bytes(pos, col_prefix, col_prefix_len))
1413 if (prev_end != pos)
1415 printf ("%04x ", prev_end);
1416 hex_dump (stdout, prev_end, pos - prev_end);
1419 printf ("col %d\n", data[pos + 3]);
1420 pos += col_prefix_len - 1;
1425 static const int heading_prefix[] = {
1426 -1, 0x00, 0x00, 0x00, 0x50, 0x80, 0x00, 0x52, 0x80, 0x00, -1, 0x00,
1427 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
1428 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1429 0x00, 0x05, 0x80, 0x01, 0x02, 0x28, 0x05, 0x00, 0x01
1431 size_t heading_prefix_len = sizeof heading_prefix / sizeof *heading_prefix;
1432 if (match_bytes(pos, heading_prefix, heading_prefix_len))
1434 if (prev_end != pos)
1436 printf ("%04x ", prev_end);
1437 hex_dump (stdout, prev_end, pos - prev_end);
1440 printf ("heading %d %d\n", data[pos],data[pos + 10]);
1441 pos += heading_prefix_len - 1;
1446 static const int font_prefix[] = {
1447 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, 0x80, 0x00, 0x01, 0x00,
1448 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, -1,
1449 0x80, 0x00, -1, 0x00, -1, 0x00, 0xc8, 0x00, -1, -1, -1, -1, -1,
1450 0x00, -1, 0x00, 0x00, 0x00, 0x01, 0x00, -1,
1451 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1452 0x00, 0x00, 0x00, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1453 0x00, 0x00, -1 /* 12 or 22 */,
1455 size_t font_prefix_len = sizeof font_prefix / sizeof *font_prefix;
1456 if (match_bytes(pos, font_prefix, font_prefix_len))
1458 if (prev_end != pos)
1460 printf ("%04x", prev_end);
1461 hex_dump (stdout, prev_end, pos - prev_end);
1464 printf ("font %d %d %d %d %d %d %d %d %d %d\n",
1465 data[pos + 24], data[pos + 26],
1466 data[pos + 30], data[pos + 31], data[pos + 32],
1467 data[pos + 33], data[pos + 34], data[pos + 36],
1468 data[pos + 58], data[pos + 59]);
1469 pos += font_prefix_len - 1;
1474 static const int table_prefix[] = {
1475 -1 /* ed or e9 */, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
1476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x00,
1477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x41, 0x72, 0x69,
1478 0x61, 0x6c, 0x00, -1, 0x00, -1, 0x00, 0x00, 0x00, 0x00, 0x00,
1479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
1481 0x00, 0x00, 0x00, 0x00, -1, 0x00, 0x00, 0x00, -1,
1483 size_t table_prefix_len = sizeof table_prefix / sizeof *table_prefix;
1484 if (match_bytes(pos, table_prefix, table_prefix_len))
1486 if (prev_end != pos)
1488 printf ("%04x", prev_end);
1489 hex_dump (stdout, prev_end, pos - prev_end);
1492 printf ("table %d\n", data[pos + 72]);
1493 pos += table_prefix_len - 1;
1498 static const int dim_prefix[] = {
1499 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, -1,
1500 0x00, 0x00, 0x00, 0x00, -1, 0x80, 0x01, 0x02, -1,
1501 -1, -1, -1 /* 00 or 01 */,
1503 size_t dim_prefix_len = sizeof dim_prefix / sizeof *dim_prefix;
1504 if (match_bytes(pos, dim_prefix, dim_prefix_len))
1506 if (prev_end != pos)
1508 printf ("%04x", prev_end);
1509 hex_dump (stdout, prev_end, pos - prev_end);
1512 printf ("dim %d %d %d %d %d\n", data[pos + 8], data[pos + 13],
1513 data[pos + 17], data[pos + 18], data[pos + 19]);
1514 pos += dim_prefix_len - 1;
1519 static const int dim2_prefix[] = {
1520 0x50, 0x80, 0x00, 0x52, 0x80, 0x00, -1, 0x00, 0x00, 0x00, -1, 0, 0, 0,
1523 size_t dim2_prefix_len = sizeof dim2_prefix / sizeof *dim2_prefix;
1524 if (match_bytes(pos, dim2_prefix, dim2_prefix_len))
1526 if (prev_end != pos)
1528 printf ("%04x", prev_end);
1529 hex_dump (stdout, prev_end, pos - prev_end);
1532 int16_t x = *(int16_t *) &data[pos + 14];
1533 int16_t y = *(int16_t *) &data[pos + 16];
1534 printf ("dim2 %d %d %d %d\n", data[pos + 6], data[pos + 10], x, y);
1535 pos += dim2_prefix_len - 1;
1540 if (!is_ascii(data[pos]))
1543 unsigned int start = pos;
1544 unsigned int end = pos + 1;
1545 while (is_ascii(data[end]))
1548 unsigned int len = end - start;
1552 unsigned int len2 = data[start - 2] + (data[start - 1] << 8);
1553 unsigned int len3 = data[start - 1];
1555 if (len2 && len2 <= len)
1560 else if (len3 && len3 <= len)
1571 unsigned real_start = start - length_bytes;
1572 if (prev_end != real_start)
1574 printf ("%04x ", prev_end);
1575 hex_dump (stdout, prev_end, real_start - prev_end);
1577 printf ("%04x \"%.*s\"\n", real_start,
1578 (int) end - start, (char *) &data[start]);