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 int len = data[pos] + data[pos + 1] * 256;
311 char *s = malloc(len + 1);
313 memcpy(s, &data[pos + 4], len);
320 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
324 #define get_string4() get_string4(WHERE)
327 get_padded_string(int len)
329 char *s = xmemdup0(&data[pos], len);
335 get_string_be(const char *where)
338 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
339 /*&& all_ascii(&data[pos + 4], data[pos])*/)
341 int len = data[pos + 2] * 256 + data[pos + 3];
342 char *s = malloc(len + 1);
344 memcpy(s, &data[pos + 4], len);
351 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
355 #define get_string_be() get_string_be(WHERE)
364 static void __attribute__((unused))
365 hex_dump(FILE *stream, int ofs, int n)
368 for (int i = 0; i < n; i++)
370 int c = data[ofs + i];
371 n_ascii += is_ascii(c);
372 fprintf(stream, " %02x", c);
377 for (int i = 0; i < n; i++)
379 int c = data[ofs + i];
380 putc(c >= 32 && c < 127 ? c : '.', stream);
386 static void __attribute__((unused))
387 char_dump(FILE *stream, int ofs, int n)
389 for (int i = 0; i < n; i++)
391 int c = data[ofs + i];
392 putc(c >= 32 && c < 127 ? c : '.', stream);
399 compare_int(const void *a_, const void *b_)
403 return *a < *b ? -1 : *a > *b;
408 format_name (int format, char *buf)
413 case 2: return "AHEX";
414 case 3: return "COMMA";
415 case 4: return "DOLLAR";
416 case 5: case 40: return "F";
418 case 7: return "PIBHEX";
420 case 9: return "PIB";
421 case 10: return "PK";
422 case 11: return "RB";
423 case 12: return "RBHEX";
427 case 20: return "DATE";
428 case 21: return "TIME";
429 case 22: return "DATETIME";
430 case 23: return "ADATE";
431 case 24: return "JDATE";
432 case 25: return "DTIME";
433 case 26: return "WKDAY";
434 case 27: return "MONTH";
435 case 28: return "MOYR";
436 case 29: return "QYR";
437 case 30: return "WKYR";
438 case 31: return "PCT";
439 case 32: return "DOT";
440 case 33: return "CCA";
441 case 34: return "CCB";
442 case 35: return "CCC";
443 case 36: return "CCD";
444 case 37: return "CCE";
445 case 38: return "EDATE";
446 case 39: return "SDATE";
447 default: sprintf(buf, "(%d)", format); return buf;
456 int fmt = data[pos++];
458 printf ("%s%d.%d", format_name(fmt, buf), w, d);
462 parse_heading(const char *name)
464 match_u16_assert(0xffff);
466 match_string2_assert(name);
470 match_zeros_assert(int count, const char *where)
472 for (int i = 0; i < count; i++)
476 "%s: %#x: expected %d zeros here but offset %d is %#"PRIx8"\n",
477 where, pos, count, i, data[pos + i]);
482 #define match_zeros_assert(count) match_zeros_assert(count, WHERE)
485 put_safe(const char *s)
493 else if (*s < 0x20 || *s > 0x7e)
494 printf ("\\x%02"PRIx8, (uint8_t) *s);
502 parse_DspString(void)
506 printf("DspString(%f, \"", get_double());
507 printf("%s\")\n", get_string1());
511 match_byte_assert(1);
512 printf ("DspString(");
515 match_byte_assert(0);
516 match_byte_assert(1);
517 put_safe(get_string1());
523 match_DspString(void)
525 match_byte_assert(5);
526 match_byte_assert(0x80);
531 match_DspSimpleText(void)
533 match_byte_assert(3);
534 match_byte_assert(0x80);
535 match_zeros_assert(5);
536 if (!match_byte(0x10))
537 match_byte_assert(0);
538 match_zeros_assert(4);
542 match_NavTreeViewItem(void)
544 match_byte_assert(7);
545 match_byte_assert(0x80);
546 match_zeros_assert(1);
547 if (!match_byte(0) && !match_byte(7))
548 match_byte_assert(8);
549 match_zeros_assert(3);
551 match_byte_assert(0);
552 match_byte_assert(1);
553 match_zeros_assert(3);
555 match_byte_assert(1);
556 match_zeros_assert(5);
557 match_byte_assert(1);
558 match_zeros_assert(5);
560 put_safe(get_string1());
565 parse_DspNumber(void)
567 match_byte_assert(1);
568 printf("DspNumber(");
570 match_byte_assert(0x80);
572 printf (" %f", get_double());
573 printf (" \"%s\")\n", get_string1());
577 match_DspNumber(void)
579 match_byte_assert(0x2a);
580 match_byte_assert(0x80);
584 static void parse_flexible(void);
589 match_byte_assert(0);
590 match_DspSimpleText();
591 parse_flexible(); /* DspString or DspNumber. */
597 match_byte_assert(0x27);
598 match_byte_assert(0x80);
603 parse_PMModelItemInfo(void)
605 match_byte_assert(0);
606 pos += 1; /* Counter */
607 match_zeros_assert(7);
610 match_byte_assert(0xe);
611 match_byte_assert(0);
615 match_PMModelItemInfo(void)
617 match_byte_assert(0x54);
618 match_byte_assert(0x80);
619 parse_PMModelItemInfo();
620 match_DspSimpleText();
625 match_PMPivotItemTree(void)
627 match_byte_assert(0x52);
628 match_byte_assert(0x80);
629 match_byte_assert(0);
630 match_PMModelItemInfo();
636 if (data[pos] == 0xff && data[pos + 1] == 0xff)
638 match_u16_assert(0xffff);
640 char *heading = get_string2();
641 if (!strcmp(heading, "DspCell"))
643 else if (!strcmp(heading, "DspNumber"))
645 else if (!strcmp(heading, "DspString"))
650 else if (data[pos] == 0x2a && data[pos + 1] == 0x80)
652 else if (data[pos] == 0x27 && data[pos + 1] == 0x80)
654 else if (data[pos] == 0x5 && data[pos + 1] == 0x80)
656 else if ((data[pos] == 0x3c || data[pos] == 0x39)
657 && data[pos + 1] == 0x80)
663 /* match_byte_assert(0x01);
664 match_byte_assert(0x02);
665 match_byte_assert(0x0d); */
667 else if (data[pos] == 0x15 && data[pos + 1] == 0x80)
671 match_byte_assert(2);
672 printf ("15 80(%f", get_double());
673 printf (" %s)\n", get_string1());
677 fprintf (stderr, "bad data cell 0x%02x at offset %x\n",
679 hex_dump (stderr, pos, 64);
685 main(int argc, char *argv[])
687 bool print_offsets = false;
690 int c = getopt (argc, argv, "o");
697 print_offsets = true;
704 if (argc - optind != 1)
706 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
710 const char *filename = argv[optind];
711 int fd = open(filename, O_RDONLY);
714 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
731 if (read(fd, data, n) != n)
738 setvbuf (stdout, NULL, _IOLBF, 0);
740 match_byte_assert(4);
742 match_string1_assert("SPSS Output Document");
744 match_byte_assert(0x63);
746 parse_heading("NavRoot");
747 match_byte_assert(2);
748 match_zeros_assert(32);
750 parse_heading("DspSimpleText");
751 match_zeros_assert(10);
753 parse_heading("DspString");
756 parse_heading("NavTreeViewItem");
757 match_byte_assert(0);
759 match_byte_assert(2);
760 match_byte_assert(0);
761 match_byte_assert(1);
762 match_zeros_assert(9);
764 assert (pos == 0xb0);
767 match_zeros_assert(5);
769 match_u32_assert(11000);
772 match_u32_assert(11000);
773 match_u32_assert(8500);
776 match_string1_assert("(Continued)");
777 match_byte_assert(1);
778 match_byte_assert(1);
779 match_zeros_assert(3);
780 get_string4(); /* page title */
781 match_byte_assert(1);
782 match_byte_assert(1);
783 match_zeros_assert(3);
784 get_string4(); /* page number */
785 match_byte_assert(0);
789 parse_heading("NavLog");
791 puts(get_padded_string(32));
793 match_u32_assert(132);
794 match_zeros_assert(8);
797 match_byte_assert(0);
799 parse_heading("NavHead");
800 match_byte_assert(2);
801 match_zeros_assert(24);
804 match_DspSimpleText();
806 match_NavTreeViewItem();
807 match_zeros_assert(3);
809 parse_heading("NavTitle");
811 match_DspSimpleText();
813 match_NavTreeViewItem();
815 match_byte_assert(1);
816 match_byte_assert(1);
817 match_u32_assert(-19);
818 match_zeros_assert(12);
819 match_byte_assert(0xbc);
820 match_byte_assert(2);
821 match_zeros_assert(9);
822 match_byte_assert(0x22);
823 puts(get_padded_string(32));
824 match_u32_assert(80);
825 match_zeros_assert(8);
828 match_byte_assert(0);
830 parse_heading("NavNote");
831 match_byte_assert(2);
832 match_zeros_assert(8);
833 match_u32_assert(24);
835 match_u32_assert(-40);
839 match_DspSimpleText();
841 match_NavTreeViewItem();
842 match_byte_assert(1);
844 parse_heading("PTPivotController");
845 match_byte_assert(2);
847 match_u32_assert(100);
848 match_u32_assert(100);
849 match_u32_assert(100);
850 match_u32_assert(100);
852 parse_heading("PVPivotView");
854 match_byte_assert(0);
856 parse_heading("PMPivotModel");
857 match_byte_assert(3);
859 parse_heading("NDimensional__DspCell");
860 match_byte_assert(0);
863 parse_heading("IndexedCollection");
864 match_byte_assert(0);
866 match_zeros_assert(3);
867 match_byte_assert(1);
868 match_byte_assert(0);
870 while (data[pos] != 1)
878 match_byte_assert(1);
879 match_byte_assert(0);
885 match_byte_assert(0);
886 match_byte_assert(1);
887 match_byte_assert(0);
888 match_byte_assert(0);
889 match_byte_assert(0);
890 match_byte_assert(1);
891 match_byte_assert(0);
895 parse_heading("PMPivotItemTree");
896 match_byte_assert(0);
898 parse_heading("AbstractTreeBranch");
899 match_byte_assert(0);
901 parse_heading("PMModelItemInfo");
902 parse_PMModelItemInfo();
903 match_DspSimpleText();
907 match_PMPivotItemTree();
910 match_PMPivotItemTree();
913 match_PMPivotItemTree();
916 match_PMPivotItemTree();
919 match_PMPivotItemTree();
922 match_PMPivotItemTree();
925 match_PMPivotItemTree();
928 match_PMPivotItemTree();
931 match_PMPivotItemTree();
934 match_PMPivotItemTree();
937 match_PMPivotItemTree();
940 match_PMPivotItemTree();
943 match_PMPivotItemTree();
946 match_PMPivotItemTree();
949 match_PMPivotItemTree();
952 match_PMPivotItemTree();
955 match_PMPivotItemTree();
961 while (data[pos] != 0xff || data[pos + 1] != 0xff)
963 parse_heading("PVViewDimension");
966 for (i = 0; data[pos + i] != 0xff || data[pos + i + 1] != 0xff; i++)
968 hex_dump(stdout, pos, i);
970 printf ("%#x: end of successful parse\n", pos);