14 #include "u8-mbtouc.h"
16 static const char *filename;
27 #define STR(x) XSTR(x)
28 #define WHERE __FILE__":" STR(__LINE__)
30 static void __attribute__((unused))
31 hex_dump(FILE *stream, int ofs, int n);
43 memcpy(&x, &data[pos], 4);
48 static unsigned long long int
52 memcpy(&x, &data[pos], 8);
61 x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
70 memcpy(&x, &data[pos], 2);
79 memcpy(&x, &data[pos], 8);
84 static double __attribute__((unused))
88 memcpy(&x, &data[pos], 4);
103 match_u16(uint16_t x)
112 match_u32_assert(uint32_t x, const char *where)
114 unsigned int y = get_u32();
117 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u: ", where, pos - 4, x, y);
118 hex_dump(stderr, pos - 4, 64);
122 #define match_u32_assert(x) match_u32_assert(x, WHERE)
125 match_u16_assert(uint16_t x, const char *where)
127 unsigned int y = get_u16();
130 fprintf(stderr, "%s: 0x%x: expected u16:%u, got u16:%u: ", where, pos - 2, x, y);
131 hex_dump(stderr, pos - 2, 64);
135 #define match_u16_assert(x) match_u16_assert(x, WHERE)
137 static bool __attribute__((unused))
138 match_u64(uint64_t x)
146 static void __attribute__((unused))
147 match_u64_assert(uint64_t x, const char *where)
149 unsigned long long int y = get_u64();
152 fprintf(stderr, "%s: 0x%x: expected u64:%lu, got u64:%llu\n", where, pos - 8, x, y);
156 #define match_u64_assert(x) match_u64_assert(x, WHERE)
158 static bool __attribute__((unused))
159 match_be32(uint32_t x)
168 match_be32_assert(uint32_t x, const char *where)
170 unsigned int y = get_be32();
173 fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
177 #define match_be32_assert(x) match_be32_assert(x, WHERE)
180 match_byte(uint8_t b)
182 if (pos < n && data[pos] == b)
192 match_byte_assert(uint8_t b, const char *where)
196 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x: ", where, pos, b, data[pos]);
197 hex_dump(stderr, pos, 64);
201 #define match_byte_assert(b) match_byte_assert(b, WHERE)
204 match_bytes(int start, const int *bytes, size_t n_bytes)
206 for (size_t i = 0; i < n_bytes; i++)
207 if (bytes[i] >= 0 && data[start + i] != bytes[i])
213 xmemdup0(const void *p, size_t n)
215 char *s = malloc(n + 1);
226 match_byte_assert(1);
230 static bool __attribute__((unused))
233 return (p >= ' ' && p < 127) || p == '\r' || p == '\n' || p == '\t';
237 count_zeros(const uint8_t *p)
245 static bool __attribute__((unused))
246 all_utf8(const char *p_, size_t len)
248 const uint8_t *p = (const uint8_t *) p_;
249 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
253 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
254 if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
261 pull_string(int len, const char *where)
264 for (int i = 0; i < len - 1; i++)
267 fprintf(stderr, "%s: %d-byte string starting at 0x%x has null byte "
268 "at offset %d: ", where, len, pos, i);
269 hex_dump(stderr, pos, len + 64);
273 char *s = xmemdup0(&data[pos], len);
279 get_string2(const char *where)
281 return pull_string(get_u16(), where);
283 #define get_string2() get_string2(WHERE)
286 get_string1(const char *where)
288 int len = data[pos++];
289 return len == 0xff ? (get_string2)(where) : pull_string(len, where);
291 #define get_string1() get_string1(WHERE)
294 match_string1_assert(const char *exp, const char *where)
297 char *act = (get_string1)(where);
298 if (strcmp(act, exp))
300 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
301 where, start, exp, act);
305 #define match_string1_assert(x) match_string1_assert(x, WHERE)
308 match_string2_assert(const char *exp, const char *where)
311 char *act = (get_string2)(where);
312 if (strcmp(act, exp))
314 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
315 where, start, exp, act);
319 #define match_string2_assert(x) match_string2_assert(x, WHERE)
322 get_string4(const char *where)
324 assert(data[pos + 3] == 0);
325 return pull_string(get_u32(), where);
327 #define get_string4() get_string4(WHERE)
330 get_padded_string(int len)
332 char *s = xmemdup0(&data[pos], len);
338 get_string_be(const char *where)
341 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
342 /*&& all_ascii(&data[pos + 4], data[pos])*/)
344 int len = data[pos + 2] * 256 + data[pos + 3];
345 char *s = malloc(len + 1);
347 memcpy(s, &data[pos + 4], len);
354 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
358 #define get_string_be() get_string_be(WHERE)
367 static void __attribute__((unused))
368 hex_dump(FILE *stream, int ofs, int n)
371 for (int i = 0; i < n; i++)
373 int c = data[ofs + i];
374 n_ascii += is_ascii(c);
375 fprintf(stream, " %02x", c);
380 for (int i = 0; i < n; i++)
382 int c = data[ofs + i];
383 putc(c >= 32 && c < 127 ? c : '.', stream);
389 static void __attribute__((unused))
390 char_dump(FILE *stream, int ofs, int n)
392 for (int i = 0; i < n; i++)
394 int c = data[ofs + i];
395 putc(c >= 32 && c < 127 ? c : '.', stream);
402 compare_int(const void *a_, const void *b_)
406 return *a < *b ? -1 : *a > *b;
411 format_name (int format, char *buf)
416 case 2: return "AHEX";
417 case 3: return "COMMA";
418 case 4: return "DOLLAR";
419 case 5: case 40: return "F";
421 case 7: return "PIBHEX";
423 case 9: return "PIB";
424 case 10: return "PK";
425 case 11: return "RB";
426 case 12: return "RBHEX";
430 case 20: return "DATE";
431 case 21: return "TIME";
432 case 22: return "DATETIME";
433 case 23: return "ADATE";
434 case 24: return "JDATE";
435 case 25: return "DTIME";
436 case 26: return "WKDAY";
437 case 27: return "MONTH";
438 case 28: return "MOYR";
439 case 29: return "QYR";
440 case 30: return "WKYR";
441 case 31: return "PCT";
442 case 32: return "DOT";
443 case 33: return "CCA";
444 case 34: return "CCB";
445 case 35: return "CCC";
446 case 36: return "CCD";
447 case 37: return "CCE";
448 case 38: return "EDATE";
449 case 39: return "SDATE";
450 default: sprintf(buf, "(%d)", format); return buf;
459 int fmt = data[pos++];
461 printf ("%s%d.%d", format_name(fmt, buf), w, d);
465 parse_heading(const char *name)
467 match_u16_assert(0xffff);
469 match_string2_assert(name);
470 printf("%#x: %s\n", pos, name);
474 match_zeros_assert(int count, const char *where)
476 for (int i = 0; i < count; i++)
480 "%s: %#x: expected %d zeros here but offset %d is %#"PRIx8": ",
481 where, pos, count, i, data[pos + i]);
482 hex_dump (stderr, pos, 64);
487 #define match_zeros_assert(count) match_zeros_assert(count, WHERE)
490 put_safe(const char *s)
498 else if (*s < 0x20 || *s > 0x7e)
499 printf ("\\x%02"PRIx8, (uint8_t) *s);
506 static void parse_flexible(void);
510 parse_DspString(void)
512 printf("%#x: DspString#%d(", pos, count++);
515 printf("%f, \"", get_double());
516 printf("%s\")\n", get_string1());
520 match_byte_assert(1);
523 match_byte_assert(0);
524 match_byte_assert(1);
525 put_safe(get_string1());
532 match_DspString(void)
534 match_byte_assert(5);
535 match_byte_assert(0x80);
540 parse_DspSimpleText(void)
542 match_byte_assert(0);
545 match_zeros_assert(3);
546 if (!match_byte(0x10))
547 match_byte_assert(0);
548 match_zeros_assert(4);
550 /* Followed by DspString or DspNumber. */
554 match_DspSimpleText(void)
556 match_byte_assert(3);
557 match_byte_assert(0x80);
558 parse_DspSimpleText();
562 parse_weirdness(void)
564 match_byte_assert(1);
566 match_zeros_assert(12);
567 pos++; /* 90 or BC */
569 match_byte_assert(1);
570 match_zeros_assert(5);
572 match_zeros_assert(3);
573 puts(get_padded_string(32));
577 parse_NavTreeViewItem(void)
580 match_zeros_assert(1);
581 if (!match_byte(0) && !match_byte(7) && !match_byte(2) && !match_byte(0xc))
582 match_byte_assert(8);
583 match_zeros_assert(3);
585 match_byte_assert(0);
586 match_byte_assert(1);
587 match_byte_assert(0);
590 match_byte_assert(0);
592 match_byte_assert(0);
593 match_zeros_assert(5);
595 match_byte_assert(1);
596 match_zeros_assert(5);
603 match_byte_assert(0);
605 match_zeros_assert(11);
606 match_byte_assert(1);
607 match_zeros_assert(3);
609 match_byte_assert(0);
612 match_zeros_assert(2);
614 match_u32_assert(11000);
617 match_u32_assert(11000);
618 match_u32_assert(8500);
623 match_byte_assert(1);
628 get_string4(); /* page title */
629 match_byte_assert(1);
630 match_byte_assert(1);
631 match_zeros_assert(3);
632 get_string4(); /* page number */
633 match_byte_assert(0);
641 match_zeros_assert(3);
643 //fprintf(stderr, "%#x ", pos - 16);
644 hex_dump(stdout, start_pos, pos - start_pos);
648 match_NavTreeViewItem(void)
650 match_byte_assert(7);
651 match_byte_assert(0x80);
652 parse_NavTreeViewItem();
656 parse_DspNumber(void)
658 printf("%#x: DspNumber#%d(", pos, count++);
659 match_byte_assert(1);
661 match_byte_assert(0x80);
663 printf (" %f", get_double());
664 printf (" \"%s\")\n", get_string1());
668 match_DspNumber(void)
670 if (!match_byte(0x18) && !match_byte(0x19))
671 match_byte_assert(0x2a);
672 match_byte_assert(0x80);
679 match_byte_assert(0);
685 match_byte_assert(0x27);
686 match_byte_assert(0x80);
693 match_byte_assert(2);
700 match_byte_assert(9);
701 match_byte_assert(0x80);
706 parse_category(int level, int j, int *n_leaves)
708 for (size_t k = 0; k < level; k++)
710 get_u16(); match_byte_assert(0);
711 get_u16(); match_byte_assert(0);
712 int leaf_idx = get_u32();
713 printf("%d ", leaf_idx);
715 if (get_u16() == 0xffff)
716 match_u16_assert(0xffff);
717 else if (!match_u16(0))
718 match_u16_assert(0x0e74);
719 match_byte_assert(0);
720 match_DspSimpleText();
721 if (match_u16(0x8018))
723 printf("18 80(%02x %02x %02x) ",
724 data[pos], data[pos + 1], data[pos + 2]);
727 if (match_u16(0x8011))
731 for (size_t i = 0; i < 16; i++)
732 printf("%s%02x", i > 0 ? " " : "", data[pos++]);
737 int n_subcategories = get_u32();
739 assert (leaf_idx == 0);
742 assert (leaf_idx == *n_leaves);
745 for (int k = 0; k < n_subcategories; k++)
746 parse_category(level + 1, k, n_leaves);
750 parse_dimension(int i)
752 printf ("%#x: dimension %d\n", pos, i);
755 match_zeros_assert(5);
759 match_zeros_assert(6);
761 int n_units16 = get_u32();
763 for (int j = 0; j < n_units16; j++)
766 match_byte_assert(0);
768 int n_units32 = get_u32();
770 for (int j = 0; j < n_units32; j++)
773 get_u16(); match_byte_assert(0);
775 get_u16(); match_byte_assert(0);
776 get_u16(); match_byte_assert(0);
784 if (!match_u16(0xffff))
785 match_u16_assert(0x0e74);
786 match_byte_assert(0);
787 match_DspSimpleText();
791 int n_categories = get_u32();
792 for (int j = 0; j < n_categories; j++)
793 parse_category(1, j, &n_leaves);
797 parse_PMModelItemInfo(void)
799 for (int i = 0; i < n_dims; i++)
801 printf("%#x: end of model\n", pos);
806 match_PMModelItemInfo(void)
808 match_byte_assert(0x54);
809 match_byte_assert(0x80);
810 parse_PMModelItemInfo();
816 match_PMPivotItemTree(void)
818 match_byte_assert(0x52);
819 match_byte_assert(0x80);
820 match_byte_assert(0);
821 match_PMModelItemInfo();
827 match_byte_assert(2);
828 match_zeros_assert(24);
829 match_byte_assert(1);
830 match_zeros_assert(3);
832 match_byte_assert(0);
833 match_zeros_assert(3);
838 parse_NavOleItem(void)
840 match_byte_assert(0);
841 match_byte_assert(1);
842 match_zeros_assert(2);
844 match_zeros_assert(9);
845 match_byte_assert(1);
846 match_zeros_assert(10);
847 match_byte_assert(1);
848 match_zeros_assert(5);
850 match_byte_assert(1);
852 match_byte_assert(0);
854 match_zeros_assert(11);
855 match_byte_assert(1);
856 match_zeros_assert(3);
858 match_byte_assert(0);
862 match_NavOleItem(void)
863 { /* 0e 80 or 12 80*/
864 if (!match_byte(0x12))
865 match_byte_assert(0x0e);
866 match_byte_assert(0x80);
873 match_byte_assert(2);
874 match_zeros_assert(8);
875 match_u32_assert(24);
879 match_byte_assert(4);
880 match_zeros_assert(2);
890 match_byte_assert(2);
891 match_zeros_assert(8);
892 match_u32_assert(24);
893 if (!match_u32(0) && !match_u32(0xffffff4b))
894 match_u32_assert(-40);
903 parse_PTPivotController(void)
905 match_byte_assert(2);
907 match_u32_assert(100);
908 match_u32_assert(100);
909 match_u32_assert(100);
910 match_u32_assert(100);
914 parse_PVPivotView(void)
916 match_byte_assert(5);
917 printf ("PVPivotView(%d)\n", get_u32());
921 parse_NDimensional__DspCell(void)
923 match_byte_assert(0);
925 printf ("NDimensional__DspCell(n_dims=%d)\n", n_dims);
929 parse_IndexedCollection(void)
931 printf("IndexedCollection");
932 for (size_t i = 0; ; i++)
934 match_byte_assert(0);
935 printf("%c%d", i ? 'x' : '(', get_u32());
937 if (!match_u16(0x8011))
944 parse_PTTableLook(void)
946 match_byte_assert(2);
947 match_byte_assert(2);
948 match_zeros_assert(7);
949 match_u32_assert(0x36);
950 match_u32_assert(0x12);
954 parse_PVViewDimension(void)
956 while (data[pos + 1] != 0x80
957 && (data[pos] != 0xff || data[pos + 1] != 0xff))
965 parse_PVSeparatorStyle(void)
967 match_byte_assert(0);
968 match_byte_assert(1);
969 match_zeros_assert(15);
971 match_byte_assert(0x80);
972 match_byte_assert(0);
974 match_byte_assert(1);
975 match_zeros_assert(9);
976 while (data[pos + 1] != 0x80
977 && (data[pos] != 0xff || data[pos + 1] != 0xff))
985 parse_PVCellStyle(void)
987 match_byte_assert(0);
988 match_byte_assert(1);
989 match_zeros_assert(5);
990 match_u32_assert(0xffffff);
991 match_zeros_assert(2);
995 skip_item(const char *name)
998 printf("%#x: skipping %s bytes...", pos, name);
999 while (data[pos + 1] != 0x80
1000 && !(data[pos] == 0xff && data[pos + 1] == 0xff
1001 && data[pos + 2] == 0 && data[pos + 3] == 0))
1006 printf("until %#x:", pos);
1007 hex_dump(stdout, start_pos, pos - start_pos);
1011 parse_flexible(void)
1014 if (match_u16(0xffff))
1016 match_u16_assert(0);
1017 char *heading = get_string2();
1018 printf("%#x: %s\n", pos, heading);
1019 if (!strcmp(heading, "NavRoot"))
1021 match_byte_assert(2);
1022 match_zeros_assert(32);
1024 else if (!strcmp(heading, "NavPivot"))
1026 hex_dump(stdout, pos, 021);
1029 else if (!strcmp(heading, "DspCell"))
1031 else if (!strcmp(heading, "DspSimpleText"))
1032 parse_DspSimpleText();
1033 else if (!strcmp(heading, "DspNumber"))
1035 else if (!strcmp(heading, "DspString"))
1037 else if (!strcmp(heading, "NavHead"))
1039 else if (!strcmp(heading, "NavTreeViewItem"))
1042 parse_NavTreeViewItem();
1046 else if (!strcmp(heading, "IndexedCollection"))
1047 parse_IndexedCollection();
1048 else if (!strcmp(heading, "NavOleItem"))
1050 else if (!strcmp(heading, "NavTitle"))
1052 else if (!strcmp(heading, "NavNote"))
1054 else if (!strcmp(heading, "PTPivotController"))
1055 parse_PTPivotController();
1056 else if (!strcmp(heading, "PVPivotView"))
1057 parse_PVPivotView();
1058 else if (!strcmp(heading, "PMPivotModel"))
1059 match_byte_assert(3);
1060 else if (!strcmp(heading, "NDimensional__DspCell"))
1061 parse_NDimensional__DspCell();
1062 else if (!strcmp(heading, "PMPivotItemTree"))
1063 match_byte_assert(0);
1064 else if (!strcmp(heading, "PMModelItemInfo"))
1065 parse_PMModelItemInfo();
1066 else if (!strcmp(heading, "AbstractTreeBranch"))
1067 match_byte_assert(0);
1068 else if (!strcmp(heading, "PTTableLook"))
1069 parse_PTTableLook();
1070 else if (!strcmp(heading, "PVViewDimension"))
1071 parse_PVViewDimension();
1072 else if (!strcmp(heading, "PVSeparatorStyle"))
1073 parse_PVSeparatorStyle();
1074 else if (!strcmp(heading, "PVCellStyle"))
1075 parse_PVCellStyle();
1076 else if (!strcmp(heading, "PVTextStyle"))
1080 fprintf(stderr, "don't know %s at offset 0x%x: ", heading, start);
1081 hex_dump(stderr, pos, 128);
1085 else if (data[pos + 1] == 0x80)
1087 if ((data[pos] == 0x2a || data[pos] == 0x18 || data[pos] == 0x19) && data[pos + 1] == 0x80)
1089 else if (data[pos] == 0x27 && data[pos + 1] == 0x80)
1091 else if (data[pos] == 0x5 && data[pos + 1] == 0x80)
1093 else if (data[pos] == 0x7 && data[pos + 1] == 0x80)
1094 match_NavTreeViewItem();
1095 else if (data[pos] == 0x3 && data[pos + 1] == 0x80)
1096 match_DspSimpleText();
1097 else if ((data[pos] == 0x3c || data[pos] == 0x39)
1098 && data[pos + 1] == 0x80)
1102 printf("%#x: %02x %02x ", pos, data[pos], data[pos + 1]);
1106 /* match_byte_assert(0x01);
1107 match_byte_assert(0x02);
1108 match_byte_assert(0x0d); */
1110 else if ((data[pos] == 0x15 || data[pos] == 0x14)
1111 && data[pos + 1] == 0x80)
1118 printf ("%02x 80(%f", data[pos - 2], get_double());
1119 printf (" \"%s\")\n", get_string1());
1122 match_byte_assert(0);
1124 if (!match_byte(2) && !match_byte(3))
1125 match_byte_assert(0);
1126 match_zeros_assert(3);
1128 match_byte_assert(0);
1129 match_byte_assert(1);
1130 match_zeros_assert(3);
1131 match_byte_assert(1);
1132 match_byte_assert(0);
1137 match_byte_assert(0);
1140 else if (data[pos] == 0x17 || data[pos] == 0x25)
1142 printf("%02x %02x(%02x %02x %02x)\n",
1143 data[pos], data[pos + 1],
1144 data[pos + 2], data[pos + 3], data[pos + 4]);
1147 else if (data[pos] == 0x9 && data[pos + 1] == 0x80)
1151 else if (data[pos] == 0xe || data[pos] == 0x12)
1153 else if (data[pos] == 0x11 || data[pos] == 0x13)
1155 int type = data[pos];
1157 match_byte_assert(0);
1164 int index = get_u32();
1165 printf("%02x 80(footnote %d)\n", type, index);
1168 printf("%02x 80(%d %d)\n", type, x, y);
1171 match_zeros_assert(13);
1173 else if (data[pos] == 0x29 ||
1174 data[pos] == 0x2b ||
1175 data[pos] == 0x2d ||
1176 data[pos] == 0x31 ||
1177 data[pos] == 0x32 ||
1178 data[pos] == 0x4a ||
1179 data[pos] == 0x4c ||
1180 data[pos] == 0x4f ||
1181 data[pos] == 0x4d ||
1182 data[pos] == 0x50 ||
1183 data[pos] == 0x36 ||
1184 data[pos] == 0x52 ||
1185 data[pos] == 0x53 ||
1186 data[pos] == 0x54 ||
1187 data[pos] == 0x55 ||
1188 data[pos] == 0x57 ||
1189 data[pos] == 0x56 ||
1190 data[pos] == 0x58 ||
1191 data[pos] == 0x5c ||
1192 data[pos] == 0x5b ||
1193 data[pos] == 0x5e ||
1194 data[pos] == 0x62 ||
1195 data[pos] == 0x64 ||
1196 data[pos] == 0x4e ||
1197 data[pos] == 0x51 ||
1198 data[pos] == 0x59 ||
1199 data[pos] == 0x5a ||
1200 data[pos] == 0x5d ||
1201 data[pos] == 0x66 ||
1202 data[pos] == 0x60 ||
1203 data[pos] == 0x68 ||
1204 data[pos] == 0x48 ||
1205 data[pos] == 0x6a ||
1209 match_byte_assert(0);
1211 else if (data[pos] == 0x2c ||
1212 data[pos] == 0x2e ||
1213 data[pos] == 0x30 ||
1214 data[pos] == 0x34 ||
1215 data[pos] == 0x3d ||
1216 data[pos] == 0x40 ||
1217 data[pos] == 0x3f ||
1218 data[pos] == 0x42 ||
1219 data[pos] == 0x43 ||
1220 data[pos] == 0x44 ||
1221 data[pos] == 0x49 ||
1222 data[pos] == 0x3e ||
1225 printf ("%#x: %02x %02x(%02x %02x %02x)\n",
1226 pos, data[pos], data[pos + 1],
1227 data[pos + 2], data[pos + 3], data[pos + 4]);
1233 fprintf (stderr, "%#x: unknown record", pos);
1234 hex_dump (stderr, pos, 64);
1238 else if (match_byte(0xa))
1241 match_byte_assert(0);
1242 if (match_u16(0x0e74))
1243 match_byte_assert(0);
1246 match_zeros_assert(4);
1249 match_zeros_assert (2);
1253 else if (match_byte(1))
1255 match_byte_assert(0);
1258 match_byte_assert(0);
1261 match_zeros_assert(2);
1263 if (match_byte(0x08))
1265 match_byte_assert(0);
1266 match_u16_assert(0x0e74);
1267 match_byte_assert(0);
1269 else if (match_byte(3))
1271 match_byte_assert(0);
1272 if (match_u16(0x0e74))
1273 match_byte_assert(0);
1276 match_zeros_assert(6);
1277 if (!match_byte(0xe) && !match_byte(0x11))
1278 match_byte_assert(0);
1279 match_byte_assert(0);
1280 if (!match_u16(0x0e74))
1281 match_u16_assert(0);
1282 match_byte_assert(0);
1287 match_byte_assert(0);
1288 match_byte_assert(1);
1289 match_zeros_assert(3);
1290 match_byte_assert(1);
1291 match_byte_assert(0);
1296 else if (match_u16(1))
1298 int start_pos = pos;
1299 char *title = get_string1();
1300 printf("%#x: title(\"%s\", ", start_pos, title);
1302 match_u32_assert(0);
1303 char *id = get_string1();
1304 printf("\"%s\")\n", id);
1305 match_byte_assert(0);
1307 match_u32_assert(3);
1308 match_u16_assert(1);
1310 else //if (match_u16(2) || match_u16(3) || match_u16(4) || match_u16(5) || match_u16(6) || match_u16(7) || match_u16(8) || match_u16(9))
1311 skip_item("unknown");
1313 else if (match_byte(7) || match_byte(4) || match_byte(5) || match_byte(6) || match_byte(8) || match_byte(9) || match_byte(0xb) || match_byte(0xc) || match_byte(0x15) || match_byte(0x16) || match_byte(0x17) || match_byte(0x18) || match_byte(0x1e) || match_byte(0x1a))
1316 match_byte_assert(0);
1317 if (!match_u16(0x0e74))
1318 match_byte_assert(0);
1319 match_byte_assert(0);
1321 else if (match_byte(2) || match_byte(3))
1323 match_byte_assert(0);
1324 if (!match_u16(0x0e74))
1326 match_zeros_assert(2);
1329 match_zeros_assert(3);
1331 match_zeros_assert(4);
1336 match_u16_assert(0x0e74);
1340 //match_byte_assert(0);
1342 else if (match_byte(0xd) || match_byte(0xe) || match_byte(0xf)
1343 || match_byte(0x11) || match_byte(0x12) || match_byte(0x13)
1344 || match_byte(0x14) || match_byte(0x1b))
1346 if (!match_byte(0x07))
1347 match_byte_assert(0);
1348 if (!match_u16(0x0e74))
1349 match_zeros_assert(11);
1351 match_byte_assert(0);
1353 else if (match_byte(0xe3) || match_byte(0xdb) || match_byte(0xd8) || match_byte(0xe9) || match_byte(0xf3))
1355 match_byte_assert(0x0e);
1356 match_byte_assert(0x74);
1357 match_byte_assert(0x0e);
1358 match_byte_assert(0);
1360 else if (match_byte(0x9d) || match_byte(0x9e) || match_byte(0x9c))
1361 match_u32_assert(0x000e741a);
1362 else if (match_byte(0x10))
1364 match_byte_assert(0);
1366 match_zeros_assert(10);
1369 match_u16_assert(0x0e74);
1370 match_byte_assert(0);
1373 else if (match_byte(0x39) || match_byte(0x3a) || match_byte(0x3b))
1374 match_u32_assert(0x000e7409);
1377 //fprintf (stderr, "bad record start at offset %x: ", pos);
1378 hex_dump (stderr, pos, 64);
1387 main(int argc, char *argv[])
1389 bool print_offsets = false;
1392 int c = getopt (argc, argv, "o");
1399 print_offsets = true;
1406 if (argc - optind != 1)
1408 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
1412 const char *filename = argv[optind];
1413 int fd = open(filename, O_RDONLY);
1416 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
1427 data = malloc(n + 256);
1433 if (read(fd, data, n) != n)
1438 for (int i = 0; i < 256; i++)
1439 data[n + i] = i % 2 ? 0xaa : 0x55;
1442 setvbuf (stdout, NULL, _IONBF, 0);
1444 match_byte_assert(4);
1445 match_u32_assert(0);
1446 match_string1_assert("SPSS Output Document");
1447 match_u32_assert(1);
1448 match_byte_assert(0x63);
1462 parse_heading("NavRoot");
1463 match_byte_assert(2);
1464 match_zeros_assert(32);
1466 parse_heading("DspSimpleText");
1467 match_zeros_assert(10);
1469 parse_heading("DspString");
1472 parse_heading("NavTreeViewItem");
1473 match_byte_assert(0);
1475 match_u32_assert(0);
1476 match_byte_assert(2);
1477 match_byte_assert(0);
1478 match_byte_assert(1);
1479 match_zeros_assert(9);
1480 match_u32_assert(1);
1482 match_u32_assert(0);
1483 match_u32_assert(0x18);
1485 match_u32_assert(0xffffffd8);
1486 match_u32_assert(0xffffffde);
1487 match_u32_assert(0x18);
1489 match_u32_assert(0xffffffd8);
1490 match_u32_assert(0x28);
1491 match_u32_assert(0x28);
1495 match_zeros_assert(5);
1497 if (match_u32(8500))
1498 match_u32_assert(11000);
1501 match_u32_assert(11000);
1502 match_u32_assert(8500);
1507 match_byte_assert(1);
1512 get_string4(); /* page title */
1513 match_byte_assert(1);
1514 match_byte_assert(1);
1515 match_zeros_assert(3);
1516 get_string4(); /* page number */
1517 match_byte_assert(0);
1519 match_u16_assert(2);
1522 if (data[pos + 9] != 'L')
1524 parse_heading("NavLog");
1537 puts(get_padded_string(32));
1539 match_u32_assert(132);
1540 match_zeros_assert(8);
1541 match_u32_assert(1);
1542 printf ("0x%x\n", pos);
1544 match_byte_assert(0);
1546 parse_heading("NavHead");
1548 match_NavTreeViewItem();
1549 match_zeros_assert(3);
1551 parse_heading("NavTitle");
1553 match_DspSimpleText();
1555 match_NavTreeViewItem();
1557 match_byte_assert(1);
1558 match_byte_assert(1);
1559 match_u32_assert(-19);
1560 match_zeros_assert(12);
1561 match_byte_assert(0xbc);
1562 match_byte_assert(2);
1563 match_zeros_assert(9);
1564 match_byte_assert(0x22);
1565 puts(get_padded_string(32));
1566 match_u32_assert(80);
1567 match_zeros_assert(8);
1568 match_u32_assert(1);
1570 match_byte_assert(0);
1572 parse_heading("NavNote");
1573 match_byte_assert(2);
1574 match_zeros_assert(8);
1575 match_u32_assert(24);
1577 match_u32_assert(-40);
1579 match_u32_assert(2);
1580 match_u32_assert(1);
1581 match_DspSimpleText();
1583 match_NavTreeViewItem();
1584 match_byte_assert(1);
1586 parse_heading("PTPivotController");
1587 match_byte_assert(2);
1589 match_u32_assert(100);
1590 match_u32_assert(100);
1591 match_u32_assert(100);
1592 match_u32_assert(100);
1594 parse_heading("PVPivotView");
1595 match_u32_assert(5);
1596 match_byte_assert(0);
1598 parse_heading("PMPivotModel");
1599 match_byte_assert(3);
1601 parse_heading("NDimensional__DspCell");
1602 match_byte_assert(0);
1603 match_u32_assert(1);
1605 parse_heading("IndexedCollection");
1606 match_byte_assert(0);
1608 match_zeros_assert(3);
1609 match_byte_assert(1);
1610 match_byte_assert(0);
1611 match_zeros_assert(7);
1613 while (data[pos] != 1)
1624 match_byte_assert(1);
1625 match_byte_assert(0);
1626 puts(get_string1());
1628 match_u32_assert(2);
1629 puts(get_string1());
1631 match_byte_assert(0);
1632 match_byte_assert(1);
1633 match_byte_assert(0);
1634 match_byte_assert(0);
1635 match_byte_assert(0);
1636 match_byte_assert(1);
1637 match_byte_assert(0);
1641 parse_heading("PMPivotItemTree");
1642 match_byte_assert(0);
1644 parse_heading("AbstractTreeBranch");
1645 match_byte_assert(0);
1647 parse_heading("PMModelItemInfo");
1648 parse_PMModelItemInfo();
1649 match_DspSimpleText();
1652 match_u32_assert(7);
1653 match_PMPivotItemTree();
1655 match_u32_assert(0);
1656 match_PMPivotItemTree();
1658 match_u32_assert(0);
1659 match_PMPivotItemTree();
1661 match_u32_assert(6);
1662 match_PMPivotItemTree();
1664 match_u32_assert(0);
1665 match_PMPivotItemTree();
1667 match_u32_assert(0);
1668 match_PMPivotItemTree();
1670 match_u32_assert(0);
1671 match_PMPivotItemTree();
1673 match_u32_assert(0);
1674 match_PMPivotItemTree();
1676 match_u32_assert(0);
1677 match_PMPivotItemTree();
1679 match_u32_assert(0);
1680 match_PMPivotItemTree();
1682 match_u32_assert(2);
1683 match_PMPivotItemTree();
1685 match_u32_assert(0);
1686 match_PMPivotItemTree();
1688 match_u32_assert(0);
1689 match_PMPivotItemTree();
1691 match_u32_assert(0);
1692 match_PMPivotItemTree();
1694 match_u32_assert(0);
1695 match_PMPivotItemTree();
1697 match_u32_assert(2);
1698 match_PMPivotItemTree();
1700 match_u32_assert(0);
1701 match_PMPivotItemTree();
1703 match_u32_assert(0);
1707 while (data[pos] != 0xff || data[pos + 1] != 0xff)
1709 parse_heading("PVViewDimension");
1712 for (i = 0; data[pos + i] != 0xff || data[pos + i + 1] != 0xff; i++)
1714 hex_dump(stdout, pos, i);
1716 printf ("%#x: end of successful parse\n", pos);