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++];
256 char *s = xmemdup0(&data[pos], len);
262 match_string1_assert(const char *exp, const char *where)
265 char *act = get_string1();
266 if (strcmp(act, exp))
268 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
269 where, start, exp, act);
273 #define match_string1_assert(x) match_string1_assert(x, WHERE)
278 int len = data[pos] + data[pos + 1] * 256;
279 char *s = xmemdup0(&data[pos + 2], len);
285 match_string2_assert(const char *exp, const char *where)
288 char *act = get_string2();
289 if (strcmp(act, exp))
291 fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
292 where, start, exp, act);
296 #define match_string2_assert(x) match_string2_assert(x, WHERE)
299 get_string4(const char *where)
302 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
303 /*&& all_ascii(&data[pos + 4], data[pos])*/)
305 int len = data[pos] + data[pos + 1] * 256;
306 char *s = malloc(len + 1);
308 memcpy(s, &data[pos + 4], len);
315 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
319 #define get_string4() get_string4(WHERE)
322 get_padded_string(int len)
324 char *s = xmemdup0(&data[pos], len);
330 get_string_be(const char *where)
333 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
334 /*&& all_ascii(&data[pos + 4], data[pos])*/)
336 int len = data[pos + 2] * 256 + data[pos + 3];
337 char *s = malloc(len + 1);
339 memcpy(s, &data[pos + 4], len);
346 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
350 #define get_string_be() get_string_be(WHERE)
359 static void __attribute__((unused))
360 hex_dump(FILE *stream, int ofs, int n)
363 for (int i = 0; i < n; i++)
365 int c = data[ofs + i];
366 n_ascii += is_ascii(c);
367 fprintf(stream, " %02x", c);
372 for (int i = 0; i < n; i++)
374 int c = data[ofs + i];
375 putc(c >= 32 && c < 127 ? c : '.', stream);
381 static void __attribute__((unused))
382 char_dump(FILE *stream, int ofs, int n)
384 for (int i = 0; i < n; i++)
386 int c = data[ofs + i];
387 putc(c >= 32 && c < 127 ? c : '.', stream);
394 compare_int(const void *a_, const void *b_)
398 return *a < *b ? -1 : *a > *b;
403 format_name (int format, char *buf)
408 case 2: return "AHEX";
409 case 3: return "COMMA";
410 case 4: return "DOLLAR";
411 case 5: case 40: return "F";
413 case 7: return "PIBHEX";
415 case 9: return "PIB";
416 case 10: return "PK";
417 case 11: return "RB";
418 case 12: return "RBHEX";
422 case 20: return "DATE";
423 case 21: return "TIME";
424 case 22: return "DATETIME";
425 case 23: return "ADATE";
426 case 24: return "JDATE";
427 case 25: return "DTIME";
428 case 26: return "WKDAY";
429 case 27: return "MONTH";
430 case 28: return "MOYR";
431 case 29: return "QYR";
432 case 30: return "WKYR";
433 case 31: return "PCT";
434 case 32: return "DOT";
435 case 33: return "CCA";
436 case 34: return "CCB";
437 case 35: return "CCC";
438 case 36: return "CCD";
439 case 37: return "CCE";
440 case 38: return "EDATE";
441 case 39: return "SDATE";
442 default: sprintf(buf, "(%d)", format); return buf;
451 int fmt = data[pos++];
453 printf ("%s%d.%d", format_name(fmt, buf), w, d);
457 parse_heading(const char *name)
459 match_u16_assert(0xffff);
461 match_string2_assert(name);
465 match_zeros_assert(int count, const char *where)
467 for (int i = 0; i < count; i++)
471 "%s: %#x: expected %d zeros here but offset %d is %#"PRIx8"\n",
472 where, pos, count, i, data[pos + i]);
477 #define match_zeros_assert(count) match_zeros_assert(count, WHERE)
480 parse_DspString(void)
482 match_byte_assert(1);
483 match_byte_assert(2);
484 match_byte_assert(40);
486 match_byte_assert(5);
487 match_byte_assert(0);
488 match_byte_assert(1);
489 printf ("DspString(\"%s\")\n", get_string1());
493 match_DspString(void)
495 match_byte_assert(5);
496 match_byte_assert(0x80);
501 match_DspSimpleText(void)
503 match_byte_assert(3);
504 match_byte_assert(0x80);
505 match_zeros_assert(10);
509 match_NavTreeViewItem(void)
511 match_byte_assert(7);
512 match_byte_assert(0x80);
513 match_zeros_assert(1);
514 if (!match_byte(0) && !match_byte(7))
515 match_byte_assert(8);
516 match_zeros_assert(3);
518 match_byte_assert(0);
519 match_byte_assert(1);
520 match_zeros_assert(3);
522 match_byte_assert(1);
523 match_zeros_assert(5);
524 match_byte_assert(1);
525 match_zeros_assert(5);
530 main(int argc, char *argv[])
532 bool print_offsets = false;
535 int c = getopt (argc, argv, "o");
542 print_offsets = true;
549 if (argc - optind != 1)
551 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
555 const char *filename = argv[optind];
556 int fd = open(filename, O_RDONLY);
559 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
576 if (read(fd, data, n) != n)
583 setvbuf (stdout, NULL, _IOLBF, 0);
585 match_byte_assert(4);
587 match_string1_assert("SPSS Output Document");
589 match_byte_assert(0x63);
591 parse_heading("NavRoot");
592 match_byte_assert(2);
593 match_zeros_assert(32);
595 parse_heading("DspSimpleText");
596 match_zeros_assert(10);
598 parse_heading("DspString");
601 parse_heading("NavTreeViewItem");
602 match_byte_assert(0);
604 match_byte_assert(2);
605 match_byte_assert(0);
606 match_byte_assert(1);
607 match_zeros_assert(9);
609 assert (pos == 0xb0);
612 match_zeros_assert(5);
614 match_u32_assert(11000);
617 match_u32_assert(11000);
618 match_u32_assert(8500);
621 match_string1_assert("(Continued)");
622 match_byte_assert(1);
623 match_byte_assert(1);
624 match_zeros_assert(3);
625 get_string4(); /* page title */
626 match_byte_assert(1);
627 match_byte_assert(1);
628 match_zeros_assert(3);
629 get_string4(); /* page number */
630 match_byte_assert(0);
634 parse_heading("NavLog");
636 puts(get_padded_string(32));
638 match_u32_assert(132);
639 match_zeros_assert(8);
642 match_byte_assert(0);
644 parse_heading("NavHead");
645 match_byte_assert(2);
646 match_zeros_assert(24);
649 match_DspSimpleText();
651 match_NavTreeViewItem();
652 match_zeros_assert(3);
654 parse_heading("NavTitle");
656 match_DspSimpleText();
658 match_NavTreeViewItem();
660 match_byte_assert(1);
661 match_byte_assert(1);
662 match_u32_assert(-19);
663 match_zeros_assert(12);
664 match_byte_assert(0xbc);
665 match_byte_assert(2);
666 match_zeros_assert(9);
667 match_byte_assert(0x22);
668 puts(get_padded_string(32));
669 match_u32_assert(80);
670 match_zeros_assert(8);
673 match_byte_assert(0);
675 parse_heading("NavNote");
676 match_byte_assert(2);
677 match_zeros_assert(8);
678 match_u32_assert(24);
680 match_u32_assert(-40);
684 match_DspSimpleText();
686 match_NavTreeViewItem();
687 match_byte_assert(1);
689 parse_heading("PTPivotController");
690 match_byte_assert(2);
692 match_u32_assert(100);
693 match_u32_assert(100);
694 match_u32_assert(100);
695 match_u32_assert(100);
697 parse_heading("PVPivotView");
699 match_byte_assert(0);
701 parse_heading("PMPivotModel");
702 match_byte_assert(3);
704 parse_heading("NDimensional__DspCell");
705 match_byte_assert(0);
708 parse_heading("IndexedCollection");
709 match_byte_assert(0);
711 match_zeros_assert(3);
712 match_byte_assert(1);
713 match_byte_assert(0);
715 parse_heading("DspCell");
716 match_byte_assert(0);
717 match_DspSimpleText();
719 parse_heading("DspNumber");
720 match_byte_assert(1);
722 match_byte_assert(0x80);
724 printf (" %f", get_double());
725 printf (" \"%s\"\n", get_string1());
727 printf ("%#x: end of successful parse\n", pos);