14 #include "u8-mbtouc.h"
16 static const char *filename;
25 #define STR(x) XSTR(x)
26 #define WHERE __FILE__":" STR(__LINE__)
28 static void __attribute__((unused))
29 hex_dump(FILE *stream, int ofs, int n);
41 memcpy(&x, &data[pos], 4);
46 static unsigned long long int
50 memcpy(&x, &data[pos], 8);
59 x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
68 memcpy(&x, &data[pos], 2);
77 memcpy(&x, &data[pos], 8);
82 static double __attribute__((unused))
86 memcpy(&x, &data[pos], 4);
101 match_u16(uint16_t x)
110 match_u32_assert(uint32_t x, const char *where)
112 unsigned int y = get_u32();
115 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u: ", where, pos - 4, x, y);
116 hex_dump(stderr, pos - 4, 64);
120 #define match_u32_assert(x) match_u32_assert(x, WHERE)
123 match_u16_assert(uint16_t x, const char *where)
125 unsigned int y = get_u16();
128 fprintf(stderr, "%s: 0x%x: expected u16:%u, got u16:%u\n", where, pos - 2, x, y);
132 #define match_u16_assert(x) match_u16_assert(x, WHERE)
134 static bool __attribute__((unused))
135 match_u64(uint64_t x)
143 static void __attribute__((unused))
144 match_u64_assert(uint64_t x, const char *where)
146 unsigned long long int y = get_u64();
149 fprintf(stderr, "%s: 0x%x: expected u64:%lu, got u64:%llu\n", where, pos - 8, x, y);
153 #define match_u64_assert(x) match_u64_assert(x, WHERE)
155 static bool __attribute__((unused))
156 match_be32(uint32_t x)
165 match_be32_assert(uint32_t x, const char *where)
167 unsigned int y = get_be32();
170 fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
174 #define match_be32_assert(x) match_be32_assert(x, WHERE)
177 match_byte(uint8_t b)
179 if (pos < n && data[pos] == b)
189 match_byte_assert(uint8_t b, const char *where)
193 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x: ", where, pos, b, data[pos]);
194 hex_dump(stderr, pos, 64);
198 #define match_byte_assert(b) match_byte_assert(b, WHERE)
201 match_bytes(int start, const int *bytes, size_t n_bytes)
203 for (size_t i = 0; i < n_bytes; i++)
204 if (bytes[i] >= 0 && data[start + i] != bytes[i])
210 xmemdup0(const void *p, size_t n)
212 char *s = malloc(n + 1);
223 match_byte_assert(1);
227 static bool __attribute__((unused))
230 return (p >= ' ' && p < 127) || p == '\r' || p == '\n' || p == '\t';
234 count_zeros(const uint8_t *p)
242 static bool __attribute__((unused))
243 all_utf8(const char *p_, size_t len)
245 const uint8_t *p = (const uint8_t *) p_;
246 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
250 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
251 if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
260 int len = data[pos] + data[pos + 1] * 256;
261 char *s = xmemdup0(&data[pos + 2], len);
269 int len = data[pos++];
271 return get_string2();
274 char *s = xmemdup0(&data[pos], len);
281 match_string1_assert(const char *exp, const char *where)
284 char *act = get_string1();
285 if (strcmp(act, exp))
287 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
288 where, start, exp, act);
292 #define match_string1_assert(x) match_string1_assert(x, WHERE)
295 match_string2_assert(const char *exp, const char *where)
298 char *act = get_string2();
299 if (strcmp(act, exp))
301 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
302 where, start, exp, act);
306 #define match_string2_assert(x) match_string2_assert(x, WHERE)
309 get_string4(const char *where)
312 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
313 /*&& all_ascii(&data[pos + 4], data[pos])*/)
315 assert(data[pos + 3] == 0);
316 int len = data[pos] + data[pos + 1] * 256 + data[pos + 2] * 65536;
317 char *s = malloc(len + 1);
319 memcpy(s, &data[pos + 4], len);
326 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
330 #define get_string4() get_string4(WHERE)
333 get_padded_string(int len)
335 char *s = xmemdup0(&data[pos], len);
341 get_string_be(const char *where)
344 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
345 /*&& all_ascii(&data[pos + 4], data[pos])*/)
347 int len = data[pos + 2] * 256 + data[pos + 3];
348 char *s = malloc(len + 1);
350 memcpy(s, &data[pos + 4], len);
357 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
361 #define get_string_be() get_string_be(WHERE)
370 static void __attribute__((unused))
371 hex_dump(FILE *stream, int ofs, int n)
374 for (int i = 0; i < n; i++)
376 int c = data[ofs + i];
377 n_ascii += is_ascii(c);
378 fprintf(stream, " %02x", c);
383 for (int i = 0; i < n; i++)
385 int c = data[ofs + i];
386 putc(c >= 32 && c < 127 ? c : '.', stream);
392 static void __attribute__((unused))
393 char_dump(FILE *stream, int ofs, int n)
395 for (int i = 0; i < n; i++)
397 int c = data[ofs + i];
398 putc(c >= 32 && c < 127 ? c : '.', stream);
405 compare_int(const void *a_, const void *b_)
409 return *a < *b ? -1 : *a > *b;
414 format_name (int format, char *buf)
419 case 2: return "AHEX";
420 case 3: return "COMMA";
421 case 4: return "DOLLAR";
422 case 5: case 40: return "F";
424 case 7: return "PIBHEX";
426 case 9: return "PIB";
427 case 10: return "PK";
428 case 11: return "RB";
429 case 12: return "RBHEX";
433 case 20: return "DATE";
434 case 21: return "TIME";
435 case 22: return "DATETIME";
436 case 23: return "ADATE";
437 case 24: return "JDATE";
438 case 25: return "DTIME";
439 case 26: return "WKDAY";
440 case 27: return "MONTH";
441 case 28: return "MOYR";
442 case 29: return "QYR";
443 case 30: return "WKYR";
444 case 31: return "PCT";
445 case 32: return "DOT";
446 case 33: return "CCA";
447 case 34: return "CCB";
448 case 35: return "CCC";
449 case 36: return "CCD";
450 case 37: return "CCE";
451 case 38: return "EDATE";
452 case 39: return "SDATE";
453 default: sprintf(buf, "(%d)", format); return buf;
462 int fmt = data[pos++];
464 printf ("%s%d.%d", format_name(fmt, buf), w, d);
468 parse_heading(const char *name)
470 match_u16_assert(0xffff);
472 match_string2_assert(name);
476 match_zeros_assert(int count, const char *where)
478 for (int i = 0; i < count; i++)
482 "%s: %#x: expected %d zeros here but offset %d is %#"PRIx8": ",
483 where, pos, count, i, data[pos + i]);
484 hex_dump (stderr, pos, 64);
489 #define match_zeros_assert(count) match_zeros_assert(count, WHERE)
492 put_safe(const char *s)
500 else if (*s < 0x20 || *s > 0x7e)
501 printf ("\\x%02"PRIx8, (uint8_t) *s);
508 static void parse_flexible(void);
511 parse_DspString(void)
513 printf("%#x: DspString(", pos);
516 printf("%f, \"", get_double());
517 printf("%s\")\n", get_string1());
521 match_byte_assert(1);
524 match_byte_assert(0);
525 match_byte_assert(1);
526 put_safe(get_string1());
532 match_DspString(void)
534 match_byte_assert(5);
535 match_byte_assert(0x80);
540 match_DspSimpleText(void)
542 match_byte_assert(3);
543 match_byte_assert(0x80);
544 match_byte_assert(0);
547 match_zeros_assert(3);
548 if (!match_byte(0x10))
549 match_byte_assert(0);
550 match_zeros_assert(4);
555 parse_weirdness(void)
557 match_byte_assert(1);
559 match_zeros_assert(12);
560 pos++; /* 90 or BC */
562 match_byte_assert(1);
563 match_zeros_assert(5);
565 match_zeros_assert(3);
566 puts(get_padded_string(32));
570 match_NavTreeViewItem(void)
572 match_byte_assert(7);
573 match_byte_assert(0x80);
574 match_zeros_assert(1);
575 if (!match_byte(0) && !match_byte(7) && !match_byte(2))
576 match_byte_assert(8);
577 match_zeros_assert(3);
579 match_byte_assert(0);
580 match_byte_assert(1);
581 match_byte_assert(0);
584 match_byte_assert(0);
586 match_byte_assert(0);
587 match_zeros_assert(5);
589 match_byte_assert(1);
590 match_zeros_assert(5);
597 match_byte_assert(0);
599 match_zeros_assert(11);
600 match_byte_assert(1);
601 match_zeros_assert(3);
603 match_byte_assert(0);
606 match_zeros_assert(2);
608 match_u32_assert(11000);
611 match_u32_assert(11000);
612 match_u32_assert(8500);
617 match_byte_assert(1);
622 get_string4(); /* page title */
623 match_byte_assert(1);
624 match_byte_assert(1);
625 match_zeros_assert(3);
626 get_string4(); /* page number */
627 match_byte_assert(0);
635 match_zeros_assert(3);
637 //fprintf(stderr, "%#x ", pos - 16);
641 parse_DspNumber(void)
643 match_byte_assert(1);
644 printf("DspNumber(");
646 match_byte_assert(0x80);
648 printf (" %f", get_double());
649 printf (" \"%s\")\n", get_string1());
653 match_DspNumber(void)
655 match_byte_assert(0x2a);
656 match_byte_assert(0x80);
663 match_byte_assert(0);
664 match_DspSimpleText();
665 parse_flexible(); /* DspString or DspNumber. */
671 match_byte_assert(0x27);
672 match_byte_assert(0x80);
679 match_byte_assert(2);
686 match_byte_assert(9);
687 match_byte_assert(0x80);
692 parse_PMModelItemInfo(void)
694 match_byte_assert(0);
695 pos += 1; /* Counter */
696 match_zeros_assert(7);
699 match_byte_assert(0xe);
700 match_byte_assert(0);
704 match_PMModelItemInfo(void)
706 match_byte_assert(0x54);
707 match_byte_assert(0x80);
708 parse_PMModelItemInfo();
709 match_DspSimpleText();
714 match_PMPivotItemTree(void)
716 match_byte_assert(0x52);
717 match_byte_assert(0x80);
718 match_byte_assert(0);
719 match_PMModelItemInfo();
725 match_byte_assert(2);
726 match_zeros_assert(24);
727 match_byte_assert(1);
728 match_zeros_assert(3);
730 match_byte_assert(0);
731 match_zeros_assert(3);
732 match_DspSimpleText();
737 parse_NavOleItem(void)
739 match_byte_assert(0);
740 match_byte_assert(1);
741 match_zeros_assert(2);
743 match_zeros_assert(9);
744 match_byte_assert(1);
745 match_zeros_assert(10);
746 match_byte_assert(1);
747 match_zeros_assert(5);
749 match_byte_assert(1);
751 match_byte_assert(0);
753 match_zeros_assert(11);
754 match_byte_assert(1);
755 match_zeros_assert(3);
757 match_byte_assert(0);
761 match_NavOleItem(void)
762 { /* 0e 80 or 12 80*/
763 if (!match_byte(0x12))
764 match_byte_assert(0x0e);
765 match_byte_assert(0x80);
772 match_byte_assert(2);
773 match_zeros_assert(8);
774 match_u32_assert(24);
778 match_byte_assert(4);
779 match_zeros_assert(2);
789 match_byte_assert(2);
790 match_zeros_assert(8);
791 match_u32_assert(24);
792 if (!match_u32(0) && !match_u32(0xffffff4b))
793 match_u32_assert(-40);
801 parse_PTPivotController(void)
803 match_byte_assert(2);
805 match_u32_assert(100);
806 match_u32_assert(100);
807 match_u32_assert(100);
808 match_u32_assert(100);
812 parse_PVPivotView(void)
814 match_byte_assert(5);
815 match_zeros_assert(4);
819 parse_NDimensional__DspCell(void)
821 match_byte_assert(0);
826 parse_IndexedCollection(void)
828 match_byte_assert(0);
831 match_zeros_assert(12);
844 if (data[pos] == 0xff && data[pos + 1] == 0xff)
846 match_u16_assert(0xffff);
848 char *heading = get_string2();
849 if (!strcmp(heading, "DspCell"))
851 else if (!strcmp(heading, "DspNumber"))
853 else if (!strcmp(heading, "DspString"))
855 else if (!strcmp(heading, "NavHead"))
857 else if (!strcmp(heading, "IndexedCollection"))
858 parse_IndexedCollection();
859 else if (!strcmp(heading, "NavOleItem"))
861 else if (!strcmp(heading, "NavTitle"))
863 else if (!strcmp(heading, "NavNote"))
865 else if (!strcmp(heading, "PTPivotController"))
866 parse_PTPivotController();
867 else if (!strcmp(heading, "PVPivotView"))
869 else if (!strcmp(heading, "PMPivotModel"))
870 match_byte_assert(3);
871 else if (!strcmp(heading, "NDimensional__DspCell"))
872 parse_NDimensional__DspCell();
875 fprintf(stderr, "don't know %s at offset 0x%x: ", heading, start);
876 hex_dump(stderr, pos, 64);
880 else if (data[pos + 1] == 0x80)
882 if (data[pos] == 0x2a && data[pos + 1] == 0x80)
884 else if (data[pos] == 0x27 && data[pos + 1] == 0x80)
886 else if (data[pos] == 0x5 && data[pos + 1] == 0x80)
888 else if (data[pos] == 0x7 && data[pos + 1] == 0x80)
889 match_NavTreeViewItem();
890 else if (data[pos] == 0x3 && data[pos + 1] == 0x80)
891 match_DspSimpleText();
892 else if ((data[pos] == 0x3c || data[pos] == 0x39)
893 && data[pos + 1] == 0x80)
899 /* match_byte_assert(0x01);
900 match_byte_assert(0x02);
901 match_byte_assert(0x0d); */
903 else if (data[pos] == 0x15 && data[pos + 1] == 0x80)
909 printf ("15 80(%f", get_double());
910 printf (" %s)\n", get_string1());
913 match_zeros_assert(14);
915 else if (data[pos] == 0x9 && data[pos + 1] == 0x80)
919 else if (data[pos] == 0xe || data[pos] == 0x12)
921 else if (data[pos] == 0x11 || data[pos] == 0x13)
924 match_zeros_assert(14);
928 fprintf (stderr, "bad record 0x%02x at offset %x: ",
930 hex_dump (stderr, pos, 64);
934 else if (match_byte(0xa))
936 match_zeros_assert(5);
942 fprintf (stderr, "bad record start at offset %x: ", pos);
943 hex_dump (stderr, pos, 64);
951 main(int argc, char *argv[])
953 bool print_offsets = false;
956 int c = getopt (argc, argv, "o");
963 print_offsets = true;
970 if (argc - optind != 1)
972 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
976 const char *filename = argv[optind];
977 int fd = open(filename, O_RDONLY);
980 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
991 data = malloc(n + 256);
997 if (read(fd, data, n) != n)
1002 for (int i = 0; i < 256; i++)
1003 data[n + i] = i % 2 ? 0xaa : 0x55;
1006 setvbuf (stdout, NULL, _IOLBF, 0);
1008 match_byte_assert(4);
1009 match_u32_assert(0);
1010 match_string1_assert("SPSS Output Document");
1011 match_u32_assert(1);
1012 match_byte_assert(0x63);
1014 parse_heading("NavRoot");
1015 match_byte_assert(2);
1016 match_zeros_assert(32);
1018 parse_heading("DspSimpleText");
1019 match_zeros_assert(10);
1021 parse_heading("DspString");
1024 parse_heading("NavTreeViewItem");
1025 match_byte_assert(0);
1027 match_u32_assert(0);
1028 match_byte_assert(2);
1029 match_byte_assert(0);
1030 match_byte_assert(1);
1031 match_zeros_assert(9);
1032 match_u32_assert(1);
1034 match_u32_assert(0);
1035 match_u32_assert(0x18);
1037 match_u32_assert(0xffffffd8);
1038 match_u32_assert(0xffffffde);
1039 match_u32_assert(0x18);
1041 match_u32_assert(0xffffffd8);
1042 match_u32_assert(0x28);
1043 match_u32_assert(0x28);
1047 match_zeros_assert(5);
1049 if (match_u32(8500))
1050 match_u32_assert(11000);
1053 match_u32_assert(11000);
1054 match_u32_assert(8500);
1059 match_byte_assert(1);
1064 get_string4(); /* page title */
1065 match_byte_assert(1);
1066 match_byte_assert(1);
1067 match_zeros_assert(3);
1068 get_string4(); /* page number */
1069 match_byte_assert(0);
1071 match_u16_assert(2);
1074 if (data[pos + 9] != 'L')
1076 parse_heading("NavLog");
1096 puts(get_padded_string(32));
1098 match_u32_assert(132);
1099 match_zeros_assert(8);
1100 match_u32_assert(1);
1101 printf ("0x%x\n", pos);
1103 match_byte_assert(0);
1105 parse_heading("NavHead");
1107 match_NavTreeViewItem();
1108 match_zeros_assert(3);
1110 parse_heading("NavTitle");
1112 match_DspSimpleText();
1114 match_NavTreeViewItem();
1116 match_byte_assert(1);
1117 match_byte_assert(1);
1118 match_u32_assert(-19);
1119 match_zeros_assert(12);
1120 match_byte_assert(0xbc);
1121 match_byte_assert(2);
1122 match_zeros_assert(9);
1123 match_byte_assert(0x22);
1124 puts(get_padded_string(32));
1125 match_u32_assert(80);
1126 match_zeros_assert(8);
1127 match_u32_assert(1);
1129 match_byte_assert(0);
1131 parse_heading("NavNote");
1132 match_byte_assert(2);
1133 match_zeros_assert(8);
1134 match_u32_assert(24);
1136 match_u32_assert(-40);
1138 match_u32_assert(2);
1139 match_u32_assert(1);
1140 match_DspSimpleText();
1142 match_NavTreeViewItem();
1143 match_byte_assert(1);
1145 parse_heading("PTPivotController");
1146 match_byte_assert(2);
1148 match_u32_assert(100);
1149 match_u32_assert(100);
1150 match_u32_assert(100);
1151 match_u32_assert(100);
1153 parse_heading("PVPivotView");
1154 match_u32_assert(5);
1155 match_byte_assert(0);
1157 parse_heading("PMPivotModel");
1158 match_byte_assert(3);
1160 parse_heading("NDimensional__DspCell");
1161 match_byte_assert(0);
1162 match_u32_assert(1);
1164 parse_heading("IndexedCollection");
1165 match_byte_assert(0);
1167 match_zeros_assert(3);
1168 match_byte_assert(1);
1169 match_byte_assert(0);
1170 match_zeros_assert(7);
1172 while (data[pos] != 1)
1180 match_byte_assert(1);
1181 match_byte_assert(0);
1182 puts(get_string1());
1184 match_u32_assert(2);
1185 puts(get_string1());
1187 match_byte_assert(0);
1188 match_byte_assert(1);
1189 match_byte_assert(0);
1190 match_byte_assert(0);
1191 match_byte_assert(0);
1192 match_byte_assert(1);
1193 match_byte_assert(0);
1197 parse_heading("PMPivotItemTree");
1198 match_byte_assert(0);
1200 parse_heading("AbstractTreeBranch");
1201 match_byte_assert(0);
1203 parse_heading("PMModelItemInfo");
1204 parse_PMModelItemInfo();
1205 match_DspSimpleText();
1208 match_u32_assert(7);
1209 match_PMPivotItemTree();
1211 match_u32_assert(0);
1212 match_PMPivotItemTree();
1214 match_u32_assert(0);
1215 match_PMPivotItemTree();
1217 match_u32_assert(6);
1218 match_PMPivotItemTree();
1220 match_u32_assert(0);
1221 match_PMPivotItemTree();
1223 match_u32_assert(0);
1224 match_PMPivotItemTree();
1226 match_u32_assert(0);
1227 match_PMPivotItemTree();
1229 match_u32_assert(0);
1230 match_PMPivotItemTree();
1232 match_u32_assert(0);
1233 match_PMPivotItemTree();
1235 match_u32_assert(0);
1236 match_PMPivotItemTree();
1238 match_u32_assert(2);
1239 match_PMPivotItemTree();
1241 match_u32_assert(0);
1242 match_PMPivotItemTree();
1244 match_u32_assert(0);
1245 match_PMPivotItemTree();
1247 match_u32_assert(0);
1248 match_PMPivotItemTree();
1250 match_u32_assert(0);
1251 match_PMPivotItemTree();
1253 match_u32_assert(2);
1254 match_PMPivotItemTree();
1256 match_u32_assert(0);
1257 match_PMPivotItemTree();
1259 match_u32_assert(0);
1263 while (data[pos] != 0xff || data[pos + 1] != 0xff)
1265 parse_heading("PVViewDimension");
1268 for (i = 0; data[pos + i] != 0xff || data[pos + i + 1] != 0xff; i++)
1270 hex_dump(stdout, pos, i);
1272 printf ("%#x: end of successful parse\n", pos);