14 #include "u8-mbtouc.h"
16 static const char *filename;
25 #define STR(x) XSTR(x)
26 #define WHERE __FILE__":" STR(__LINE__)
38 memcpy(&x, &data[pos], 4);
43 static unsigned long long int
47 memcpy(&x, &data[pos], 8);
56 x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
65 memcpy(&x, &data[pos], 2);
74 memcpy(&x, &data[pos], 8);
79 static double __attribute__((unused))
83 memcpy(&x, &data[pos], 4);
107 match_u32_assert(uint32_t x, const char *where)
109 unsigned int y = get_u32();
112 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
116 #define match_u32_assert(x) match_u32_assert(x, WHERE)
119 match_u16_assert(uint16_t x, const char *where)
121 unsigned int y = get_u16();
124 fprintf(stderr, "%s: 0x%x: expected u16:%u, got u16:%u\n", where, pos - 2, x, y);
128 #define match_u16_assert(x) match_u16_assert(x, WHERE)
130 static bool __attribute__((unused))
131 match_u64(uint64_t x)
139 static void __attribute__((unused))
140 match_u64_assert(uint64_t x, const char *where)
142 unsigned long long int y = get_u64();
145 fprintf(stderr, "%s: 0x%x: expected u64:%lu, got u64:%llu\n", where, pos - 8, x, y);
149 #define match_u64_assert(x) match_u64_assert(x, WHERE)
151 static bool __attribute__((unused))
152 match_be32(uint32_t x)
161 match_be32_assert(uint32_t x, const char *where)
163 unsigned int y = get_be32();
166 fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
170 #define match_be32_assert(x) match_be32_assert(x, WHERE)
173 match_byte(uint8_t b)
175 if (pos < n && data[pos] == b)
185 match_byte_assert(uint8_t b, const char *where)
189 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
193 #define match_byte_assert(b) match_byte_assert(b, WHERE)
196 match_bytes(int start, const int *bytes, size_t n_bytes)
198 for (size_t i = 0; i < n_bytes; i++)
199 if (bytes[i] >= 0 && data[start + i] != bytes[i])
205 xmemdup0(const void *p, size_t n)
207 char *s = malloc(n + 1);
218 match_byte_assert(1);
222 static bool __attribute__((unused))
225 return (p >= ' ' && p < 127) || p == '\r' || p == '\n' || p == '\t';
229 count_zeros(const uint8_t *p)
237 static bool __attribute__((unused))
238 all_utf8(const char *p_, size_t len)
240 const uint8_t *p = (const uint8_t *) p_;
241 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
245 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
246 if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
255 int len = data[pos] + data[pos + 1] * 256;
256 char *s = xmemdup0(&data[pos + 2], len);
264 int len = data[pos++];
266 return get_string2();
269 char *s = xmemdup0(&data[pos], len);
276 match_string1_assert(const char *exp, const char *where)
279 char *act = get_string1();
280 if (strcmp(act, exp))
282 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
283 where, start, exp, act);
287 #define match_string1_assert(x) match_string1_assert(x, WHERE)
290 match_string2_assert(const char *exp, const char *where)
293 char *act = get_string2();
294 if (strcmp(act, exp))
296 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
297 where, start, exp, act);
301 #define match_string2_assert(x) match_string2_assert(x, WHERE)
304 get_string4(const char *where)
307 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
308 /*&& all_ascii(&data[pos + 4], data[pos])*/)
310 assert(data[pos + 3] == 0);
311 int len = data[pos] + data[pos + 1] * 256 + data[pos + 2] * 65536;
312 char *s = malloc(len + 1);
314 memcpy(s, &data[pos + 4], len);
321 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
325 #define get_string4() get_string4(WHERE)
328 get_padded_string(int len)
330 char *s = xmemdup0(&data[pos], len);
336 get_string_be(const char *where)
339 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
340 /*&& all_ascii(&data[pos + 4], data[pos])*/)
342 int len = data[pos + 2] * 256 + data[pos + 3];
343 char *s = malloc(len + 1);
345 memcpy(s, &data[pos + 4], len);
352 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
356 #define get_string_be() get_string_be(WHERE)
365 static void __attribute__((unused))
366 hex_dump(FILE *stream, int ofs, int n)
369 for (int i = 0; i < n; i++)
371 int c = data[ofs + i];
372 n_ascii += is_ascii(c);
373 fprintf(stream, " %02x", c);
378 for (int i = 0; i < n; i++)
380 int c = data[ofs + i];
381 putc(c >= 32 && c < 127 ? c : '.', stream);
387 static void __attribute__((unused))
388 char_dump(FILE *stream, int ofs, int n)
390 for (int i = 0; i < n; i++)
392 int c = data[ofs + i];
393 putc(c >= 32 && c < 127 ? c : '.', stream);
400 compare_int(const void *a_, const void *b_)
404 return *a < *b ? -1 : *a > *b;
409 format_name (int format, char *buf)
414 case 2: return "AHEX";
415 case 3: return "COMMA";
416 case 4: return "DOLLAR";
417 case 5: case 40: return "F";
419 case 7: return "PIBHEX";
421 case 9: return "PIB";
422 case 10: return "PK";
423 case 11: return "RB";
424 case 12: return "RBHEX";
428 case 20: return "DATE";
429 case 21: return "TIME";
430 case 22: return "DATETIME";
431 case 23: return "ADATE";
432 case 24: return "JDATE";
433 case 25: return "DTIME";
434 case 26: return "WKDAY";
435 case 27: return "MONTH";
436 case 28: return "MOYR";
437 case 29: return "QYR";
438 case 30: return "WKYR";
439 case 31: return "PCT";
440 case 32: return "DOT";
441 case 33: return "CCA";
442 case 34: return "CCB";
443 case 35: return "CCC";
444 case 36: return "CCD";
445 case 37: return "CCE";
446 case 38: return "EDATE";
447 case 39: return "SDATE";
448 default: sprintf(buf, "(%d)", format); return buf;
457 int fmt = data[pos++];
459 printf ("%s%d.%d", format_name(fmt, buf), w, d);
463 parse_heading(const char *name)
465 match_u16_assert(0xffff);
467 match_string2_assert(name);
471 match_zeros_assert(int count, const char *where)
473 for (int i = 0; i < count; i++)
477 "%s: %#x: expected %d zeros here but offset %d is %#"PRIx8"\n",
478 where, pos, count, i, data[pos + i]);
483 #define match_zeros_assert(count) match_zeros_assert(count, WHERE)
486 put_safe(const char *s)
494 else if (*s < 0x20 || *s > 0x7e)
495 printf ("\\x%02"PRIx8, (uint8_t) *s);
503 parse_DspString(void)
507 printf("DspString(%f, \"", get_double());
508 printf("%s\")\n", get_string1());
512 match_byte_assert(1);
513 printf ("DspString(");
516 match_byte_assert(0);
517 match_byte_assert(1);
518 put_safe(get_string1());
524 match_DspString(void)
526 match_byte_assert(5);
527 match_byte_assert(0x80);
532 match_DspSimpleText(void)
534 match_byte_assert(3);
535 match_byte_assert(0x80);
536 match_zeros_assert(5);
537 if (!match_byte(0x10))
538 match_byte_assert(0);
539 match_zeros_assert(4);
543 match_NavTreeViewItem(void)
545 match_byte_assert(7);
546 match_byte_assert(0x80);
547 match_zeros_assert(1);
548 if (!match_byte(0) && !match_byte(7))
549 match_byte_assert(8);
550 match_zeros_assert(3);
552 match_byte_assert(0);
553 match_byte_assert(1);
554 match_zeros_assert(3);
556 match_byte_assert(1);
557 match_zeros_assert(5);
558 match_byte_assert(1);
559 match_zeros_assert(5);
561 put_safe(get_string1());
566 parse_DspNumber(void)
568 match_byte_assert(1);
569 printf("DspNumber(");
571 match_byte_assert(0x80);
573 printf (" %f", get_double());
574 printf (" \"%s\")\n", get_string1());
578 match_DspNumber(void)
580 match_byte_assert(0x2a);
581 match_byte_assert(0x80);
585 static void parse_flexible(void);
590 match_byte_assert(0);
591 match_DspSimpleText();
592 parse_flexible(); /* DspString or DspNumber. */
598 match_byte_assert(0x27);
599 match_byte_assert(0x80);
604 parse_PMModelItemInfo(void)
606 match_byte_assert(0);
607 pos += 1; /* Counter */
608 match_zeros_assert(7);
611 match_byte_assert(0xe);
612 match_byte_assert(0);
616 match_PMModelItemInfo(void)
618 match_byte_assert(0x54);
619 match_byte_assert(0x80);
620 parse_PMModelItemInfo();
621 match_DspSimpleText();
626 match_PMPivotItemTree(void)
628 match_byte_assert(0x52);
629 match_byte_assert(0x80);
630 match_byte_assert(0);
631 match_PMModelItemInfo();
637 if (data[pos] == 0xff && data[pos + 1] == 0xff)
639 match_u16_assert(0xffff);
641 char *heading = get_string2();
642 if (!strcmp(heading, "DspCell"))
644 else if (!strcmp(heading, "DspNumber"))
646 else if (!strcmp(heading, "DspString"))
651 else if (data[pos] == 0x2a && data[pos + 1] == 0x80)
653 else if (data[pos] == 0x27 && data[pos + 1] == 0x80)
655 else if (data[pos] == 0x5 && data[pos + 1] == 0x80)
657 else if ((data[pos] == 0x3c || data[pos] == 0x39)
658 && data[pos + 1] == 0x80)
664 /* match_byte_assert(0x01);
665 match_byte_assert(0x02);
666 match_byte_assert(0x0d); */
668 else if (data[pos] == 0x15 && data[pos + 1] == 0x80)
672 match_byte_assert(2);
673 printf ("15 80(%f", get_double());
674 printf (" %s)\n", get_string1());
678 fprintf (stderr, "bad data cell 0x%02x at offset %x\n",
680 hex_dump (stderr, pos, 64);
686 main(int argc, char *argv[])
688 bool print_offsets = false;
691 int c = getopt (argc, argv, "o");
698 print_offsets = true;
705 if (argc - optind != 1)
707 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
711 const char *filename = argv[optind];
712 int fd = open(filename, O_RDONLY);
715 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
732 if (read(fd, data, n) != n)
739 setvbuf (stdout, NULL, _IOLBF, 0);
741 match_byte_assert(4);
743 match_string1_assert("SPSS Output Document");
745 match_byte_assert(0x63);
747 parse_heading("NavRoot");
748 match_byte_assert(2);
749 match_zeros_assert(32);
751 parse_heading("DspSimpleText");
752 match_zeros_assert(10);
754 parse_heading("DspString");
757 parse_heading("NavTreeViewItem");
758 match_byte_assert(0);
760 match_byte_assert(2);
761 match_byte_assert(0);
762 match_byte_assert(1);
763 match_zeros_assert(9);
765 assert (pos == 0xb0);
768 match_zeros_assert(5);
770 match_u32_assert(11000);
773 match_u32_assert(11000);
774 match_u32_assert(8500);
777 match_string1_assert("(Continued)");
778 match_byte_assert(1);
779 match_byte_assert(1);
780 match_zeros_assert(3);
781 get_string4(); /* page title */
782 match_byte_assert(1);
783 match_byte_assert(1);
784 match_zeros_assert(3);
785 get_string4(); /* page number */
786 match_byte_assert(0);
790 parse_heading("NavLog");
792 puts(get_padded_string(32));
794 match_u32_assert(132);
795 match_zeros_assert(8);
797 printf ("0x%x\n", pos);
799 match_byte_assert(0);
801 parse_heading("NavHead");
802 match_byte_assert(2);
803 match_zeros_assert(24);
806 match_DspSimpleText();
808 match_NavTreeViewItem();
809 match_zeros_assert(3);
811 parse_heading("NavTitle");
813 match_DspSimpleText();
815 match_NavTreeViewItem();
817 match_byte_assert(1);
818 match_byte_assert(1);
819 match_u32_assert(-19);
820 match_zeros_assert(12);
821 match_byte_assert(0xbc);
822 match_byte_assert(2);
823 match_zeros_assert(9);
824 match_byte_assert(0x22);
825 puts(get_padded_string(32));
826 match_u32_assert(80);
827 match_zeros_assert(8);
830 match_byte_assert(0);
832 parse_heading("NavNote");
833 match_byte_assert(2);
834 match_zeros_assert(8);
835 match_u32_assert(24);
837 match_u32_assert(-40);
841 match_DspSimpleText();
843 match_NavTreeViewItem();
844 match_byte_assert(1);
846 parse_heading("PTPivotController");
847 match_byte_assert(2);
849 match_u32_assert(100);
850 match_u32_assert(100);
851 match_u32_assert(100);
852 match_u32_assert(100);
854 parse_heading("PVPivotView");
856 match_byte_assert(0);
858 parse_heading("PMPivotModel");
859 match_byte_assert(3);
861 parse_heading("NDimensional__DspCell");
862 match_byte_assert(0);
865 parse_heading("IndexedCollection");
866 match_byte_assert(0);
868 match_zeros_assert(3);
869 match_byte_assert(1);
870 match_byte_assert(0);
872 while (data[pos] != 1)
880 match_byte_assert(1);
881 match_byte_assert(0);
887 match_byte_assert(0);
888 match_byte_assert(1);
889 match_byte_assert(0);
890 match_byte_assert(0);
891 match_byte_assert(0);
892 match_byte_assert(1);
893 match_byte_assert(0);
897 parse_heading("PMPivotItemTree");
898 match_byte_assert(0);
900 parse_heading("AbstractTreeBranch");
901 match_byte_assert(0);
903 parse_heading("PMModelItemInfo");
904 parse_PMModelItemInfo();
905 match_DspSimpleText();
909 match_PMPivotItemTree();
912 match_PMPivotItemTree();
915 match_PMPivotItemTree();
918 match_PMPivotItemTree();
921 match_PMPivotItemTree();
924 match_PMPivotItemTree();
927 match_PMPivotItemTree();
930 match_PMPivotItemTree();
933 match_PMPivotItemTree();
936 match_PMPivotItemTree();
939 match_PMPivotItemTree();
942 match_PMPivotItemTree();
945 match_PMPivotItemTree();
948 match_PMPivotItemTree();
951 match_PMPivotItemTree();
954 match_PMPivotItemTree();
957 match_PMPivotItemTree();
963 while (data[pos] != 0xff || data[pos + 1] != 0xff)
965 parse_heading("PVViewDimension");
968 for (i = 0; data[pos + i] != 0xff || data[pos + i + 1] != 0xff; i++)
970 hex_dump(stdout, pos, i);
972 printf ("%#x: end of successful parse\n", pos);