13 #include "u8-mbtouc.h"
15 static const char *filename;
24 #define STR(x) XSTR(x)
25 #define WHERE __FILE__":" STR(__LINE__)
37 memcpy(&x, &data[pos], 4);
42 static unsigned long long int
46 memcpy(&x, &data[pos], 8);
55 x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
64 memcpy(&x, &data[pos], 2);
73 memcpy(&x, &data[pos], 8);
78 static double __attribute__((unused))
82 memcpy(&x, &data[pos], 4);
106 match_u32_assert(uint32_t x, const char *where)
108 unsigned int y = get_u32();
111 fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
115 #define match_u32_assert(x) match_u32_assert(x, WHERE)
118 match_u16_assert(uint16_t x, const char *where)
120 unsigned int y = get_u16();
123 fprintf(stderr, "%s: 0x%x: expected u16:%u, got u16:%u\n", where, pos - 2, x, y);
127 #define match_u16_assert(x) match_u16_assert(x, WHERE)
129 static bool __attribute__((unused))
130 match_u64(uint64_t x)
138 static void __attribute__((unused))
139 match_u64_assert(uint64_t x, const char *where)
141 unsigned long long int y = get_u64();
144 fprintf(stderr, "%s: 0x%x: expected u64:%lu, got u64:%llu\n", where, pos - 8, x, y);
148 #define match_u64_assert(x) match_u64_assert(x, WHERE)
150 static bool __attribute__((unused))
151 match_be32(uint32_t x)
160 match_be32_assert(uint32_t x, const char *where)
162 unsigned int y = get_be32();
165 fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
169 #define match_be32_assert(x) match_be32_assert(x, WHERE)
172 match_byte(uint8_t b)
174 if (pos < n && data[pos] == b)
184 match_byte_assert(uint8_t b, const char *where)
188 fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
192 #define match_byte_assert(b) match_byte_assert(b, WHERE)
195 match_bytes(int start, const int *bytes, size_t n_bytes)
197 for (size_t i = 0; i < n_bytes; i++)
198 if (bytes[i] >= 0 && data[start + i] != bytes[i])
204 xmemdup0(const void *p, size_t n)
206 char *s = malloc(n + 1);
217 match_byte_assert(1);
221 static bool __attribute__((unused))
224 return (p >= ' ' && p < 127) || p == '\r' || p == '\n' || p == '\t';
228 count_zeros(const uint8_t *p)
236 static bool __attribute__((unused))
237 all_utf8(const char *p_, size_t len)
239 const uint8_t *p = (const uint8_t *) p_;
240 for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
244 mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
245 if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
254 int len = data[pos++];
255 char *s = xmemdup0(&data[pos], len);
263 int len = data[pos] + data[pos + 1] * 256;
264 char *s = xmemdup0(&data[pos + 2], len);
270 get_string(const char *where)
273 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
274 /*&& all_ascii(&data[pos + 4], data[pos])*/)
276 int len = data[pos] + data[pos + 1] * 256;
277 char *s = malloc(len + 1);
279 memcpy(s, &data[pos + 4], len);
286 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
290 #define get_string() get_string(WHERE)
293 get_string_be(const char *where)
296 /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
297 /*&& all_ascii(&data[pos + 4], data[pos])*/)
299 int len = data[pos + 2] * 256 + data[pos + 3];
300 char *s = malloc(len + 1);
302 memcpy(s, &data[pos + 4], len);
309 fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
313 #define get_string_be() get_string_be(WHERE)
322 static void __attribute__((unused))
323 hex_dump(FILE *stream, int ofs, int n)
326 for (int i = 0; i < n; i++)
328 int c = data[ofs + i];
329 n_ascii += is_ascii(c);
330 fprintf(stream, " %02x", c);
335 for (int i = 0; i < n; i++)
337 int c = data[ofs + i];
338 putc(c >= 32 && c < 127 ? c : '.', stream);
344 static void __attribute__((unused))
345 char_dump(FILE *stream, int ofs, int n)
347 for (int i = 0; i < n; i++)
349 int c = data[ofs + i];
350 putc(c >= 32 && c < 127 ? c : '.', stream);
357 compare_int(const void *a_, const void *b_)
361 return *a < *b ? -1 : *a > *b;
366 format_name (int format, char *buf)
371 case 2: return "AHEX";
372 case 3: return "COMMA";
373 case 4: return "DOLLAR";
374 case 5: case 40: return "F";
376 case 7: return "PIBHEX";
378 case 9: return "PIB";
379 case 10: return "PK";
380 case 11: return "RB";
381 case 12: return "RBHEX";
385 case 20: return "DATE";
386 case 21: return "TIME";
387 case 22: return "DATETIME";
388 case 23: return "ADATE";
389 case 24: return "JDATE";
390 case 25: return "DTIME";
391 case 26: return "WKDAY";
392 case 27: return "MONTH";
393 case 28: return "MOYR";
394 case 29: return "QYR";
395 case 30: return "WKYR";
396 case 31: return "PCT";
397 case 32: return "DOT";
398 case 33: return "CCA";
399 case 34: return "CCB";
400 case 35: return "CCC";
401 case 36: return "CCD";
402 case 37: return "CCE";
403 case 38: return "EDATE";
404 case 39: return "SDATE";
405 default: sprintf(buf, "(%d)", format); return buf;
412 match_byte_assert(1);
415 int fmt = get_byte();
417 printf ("%s%d.%d ", format_name (fmt, buf), w, d);
419 match_byte_assert(0x80);
420 match_byte_assert(2);
421 printf ("%f ", get_double ());
422 printf ("\"%s\"\n", get_string1 ());
426 if (data[pos] == 0xff)
428 printf ("\nff exit");
432 if (data[pos] == 0x80 && data[pos + 1] == 1)
437 int fmt = get_byte();
439 printf ("\n%% %s%d.%d\n", format_name (fmt, buf), w, d);
441 else if (data[pos] == 0x80 && data[pos + 1] == 2)
444 printf ("\n%f ", get_double ());
445 printf ("'%s'\n", get_string1 ());
447 else if (data[pos] == 0x80 && data[pos + 1] == 0 && data[pos + 2] == 3)
449 else if (data[pos] == 0x80 && count_zeros(&data[pos + 1]) == 10)
451 else if (data[pos] == 0x1 && data[pos + 1] == 0xff)
454 printf ("\n\"%s\"\n", get_string2 ());
456 else if (data[pos] == 0x1 && data[pos + 1])
459 printf ("\n\"%s\"\n", get_string1 ());
462 printf ("%02x ", get_byte());
469 static const int cell_prefix[] = {
471 0x00, 0x00, 0x00, 0x00, 0x00, -1 /* 00 or 10 */, 0x00, 0x00, 0x00, 0x00,
473 /*13 14 15 16 17 18 19 */
474 -1, 0x80, 0x01, -1, -1, -1, -1,
476 size_t cell_prefix_len = sizeof cell_prefix / sizeof *cell_prefix;
477 if (!match_bytes(pos, cell_prefix, cell_prefix_len))
479 printf ("match failed at %x\n", pos);
484 printf ("cell %s%d.%d ",
485 format_name (data[pos + 18], buf),
489 int len = cell_prefix_len;
490 if (data[pos + 19] == 0)
492 assert (data[pos + 13] == 5);
493 if (data[pos + 20] == 0)
495 int count = (data[pos + 22]);
496 printf ("%d %d \"%.*s\"",
497 data[pos + 21], data[pos + 22],
498 count, &data[pos + 23]);
501 else if (data[pos + 20] == 1
502 && data[pos + 21] == 0xff
503 && data[pos + 22] == 0xff)
506 printf ("%d \"%.*s\"", count, data[pos + 23],
510 else if (data[pos + 20] == 1 && data[pos + 21] == 255)
512 int count = data[pos + 22] + (data[pos + 23] << 8);
514 count, &data[pos + 24]);
517 else if (data[pos + 20] == 1)
519 int count = (data[pos + 21]);
521 count, &data[pos + 22]);
527 else if (data[pos + 19] == 128 && data[pos + 20] == 2)
529 /* pos + 13 is usually 22...53, and it's 3 more than the
530 " xx 80" separator between cells */
531 printf ("xxx%x ", data[pos + 13]);
532 double d = *(double *) &data[pos + 21];
539 sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
545 if (data[pos + 29] < 0xff
546 && all_utf8((char *) &data[pos + 30], data[pos + 29]))
548 printf (" \"%.*s\"", (int) data[pos + 29],
550 len += data[pos + 29] + 1;
555 else if (data[pos + 19] == 128 && data[pos + 20] == 1 &&
558 if (data[pos + 23] < 0xff
559 && all_utf8((char *) &data[pos + 24], data[pos + 23]))
561 printf (" \"%.*s\"", (int) data[pos + 23],
563 len = 24 + data[pos + 23];
570 printf ("xxx%d %d %d %d",
571 data[pos + 19], data[pos + 20],
572 data[pos + 21], data[pos + 22]);
579 dump_category (int level, uint8_t *catstart, bool *have_catstart)
581 int cat_index = get_u32();
582 assert (cat_index < 256);
585 match_u32_assert (1);
589 if (!match_u16(0xe74) && !match_u16(0xffff))
592 for (int i = 0; i < level; i++)
595 for (int i = 0; ; i++, pos++)
596 if (data[pos] == 5 && data[pos + 1] == 0x80)
601 match_byte_assert (5);
602 match_byte_assert (0x80);
607 match_byte_assert (1);
608 match_byte_assert (2);
609 match_byte_assert (0x28);
610 match_byte_assert (5);
611 match_byte_assert (0);
612 match_byte_assert (1);
614 printf (" \"%s\"", get_string1());
616 int n_children = get_u32();
617 assert (n_children < 256);
619 printf (" (group with %d children)", n_children);
621 printf (" (category #%d)", cat_index);
623 printf (" %02x %02x %02x %02x %02x %02x\n",
624 data[pos], data[pos + 1], data[pos + 2],
625 data[pos + 3], data[pos + 4], data[pos + 5]);
628 *have_catstart = true;
629 memcpy(catstart, &data[pos], 6);
633 for (int i = 0; i < n_children; i++)
634 dump_category (level + 1, catstart, have_catstart);
638 dump_PMModelItemInfo(int ndims)
642 if (data[pos + 9] && data[pos + 9] != 0xff)//count_zeros (&data[pos + 9]) < 4)
646 match_byte_assert (0);
649 bool have_catstart = false;
650 dump_category (0, catstart, &have_catstart);
651 assert(have_catstart);
653 for (int i = 1; i < ndims; i++)
655 for (int j = 0; ; j++, pos++)
658 if (!memcmp(&data[pos], catstart, 6))
663 dump_category (0, catstart, &have_catstart);
668 main(int argc, char *argv[])
670 bool print_offsets = false;
673 int c = getopt (argc, argv, "o");
680 print_offsets = true;
687 if (argc - optind != 1)
689 fprintf (stderr, "usage: %s FILE.bin", argv[0]);
693 const char *filename = argv[optind];
694 int fd = open(filename, O_RDONLY);
697 fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
714 if (read(fd, data, n) != n)
721 setvbuf (stdout, NULL, _IOLBF, 0);
726 unsigned int prev_end = 0;
727 for (pos = 0; pos + 50 < n; pos++)
729 if (data[pos + 0] == 0xff &&
730 data[pos + 1] == 0xff &&
731 data[pos + 2] == 0 &&
734 int len = data[pos + 4] + (data[pos + 5] << 8);
735 if (len < 3 || pos + len + 6 >= n || !all_utf8 ((char *) &data[pos + 6], len))
738 printf ("+%04x %04x...%04x: %-25.*s\n",
739 pos - prev_end, pos, pos + 6 + len,
740 len < 50 ? (int) len : 50, &data[pos + 6]);
741 prev_end = pos + 6 + len;
746 for (pos = 0; pos + 50 < n; pos++)
748 if (data[pos + 0] == 'L' &&
749 data[pos + 1] == 'o' &&
750 data[pos + 2] == 'g' &&
751 !all_utf8((char *) &data[pos + 3], 1) &&
752 data[pos - 1] != 'v')
755 printf ("%04x: ", pos);
756 unsigned int p = pos;
757 while (all_utf8 ((char *) &data[p], 1))
759 hex_dump (stdout, p - 28, 38);
763 unsigned int prev_end = 0;
766 for (pos = 2; pos + 50 < n; )
768 static const int cell_prefix[] = {
770 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, -1 /* 00 or 10 */, 0x00, 0x00, 0x00, 0x00, -1,
772 /*14 15 16 17 18 19 */
773 0x80, 0x01, -1, -1, -1, -1,
775 size_t cell_prefix_len = sizeof cell_prefix / sizeof *cell_prefix;
776 if (match_bytes(pos, cell_prefix, cell_prefix_len))
781 printf ("%04x ", prev_end);
782 hex_dump (stdout, prev_end, pos - prev_end);
786 printf ("cell %s%d.%d ",
787 format_name (data[pos + 18], buf),
791 int len = cell_prefix_len;
792 if (data[pos + 19] == 0)
794 assert (data[pos + 13] == 5);
795 if (data[pos + 20] == 0)
797 int count = (data[pos + 22]);
798 printf ("%d %d \"%.*s\"\n",
799 data[pos + 21], data[pos + 22],
800 count, &data[pos + 23]);
803 else if (data[pos + 20] == 1
804 && data[pos + 21] == 0xff
805 && data[pos + 22] == 0xff)
808 printf ("%d \"%.*s\"\n", count, data[pos + 23],
812 else if (data[pos + 20] == 1 && data[pos + 21] == 255)
814 int count = data[pos + 22] + (data[pos + 23] << 8);
815 printf ("\"%.*s\"\n",
816 count, &data[pos + 24]);
819 else if (data[pos + 20] == 1)
821 int count = (data[pos + 21]);
822 printf ("\"%.*s\"\n",
823 count, &data[pos + 22]);
829 else if (data[pos + 19] == 128 && data[pos + 20] == 2)
831 /* pos + 13 is usually 22...53, and it's 3 more than the
832 " xx 80" separator between cells */
833 printf ("xxx%x ", data[pos + 13]);
834 double d = *(double *) &data[pos + 21];
841 sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
847 if (data[pos + 29] < 0xff
848 && all_utf8((char *) &data[pos + 30], data[pos + 29]))
850 printf (" \"%.*s\"", (int) data[pos + 29],
852 len += data[pos + 29] + 1;
859 else if (data[pos + 19] == 128 && data[pos + 20] == 1 &&
862 if (data[pos + 23] < 0xff
863 && all_utf8((char *) &data[pos + 24], data[pos + 23]))
865 printf (" \"%.*s\"\n", (int) data[pos + 23],
867 len = 24 + data[pos + 23];
874 printf ("xxx%d %d %d %d\n",
875 data[pos + 19], data[pos + 20],
876 data[pos + 21], data[pos + 22]);
884 static const int record_prefix[] = {
885 0xff, 0xff, 0x00, 0x00,
887 size_t record_prefix_len = sizeof record_prefix / sizeof *record_prefix;
888 if (match_bytes(pos, record_prefix, record_prefix_len))
890 int len = record_prefix_len;
891 int slen = data[pos + 4] + (data[pos + 5] << 8);
892 if (slen >= 2 && slen < 256 && all_utf8((char *) &data[pos + 6], slen))
897 printf ("%04x ", prev_end);
898 hex_dump (stdout, prev_end, pos - prev_end);
903 printf ("rec:%-20.*s ", slen, &data[pos + 6]);
905 title = xmemdup0(&data[pos + 6], slen);
906 sum += data[pos+len];
910 if (!strcmp(title, "DspNumber"))
912 else if (!strcmp(title, "PMModelItemInfo"))
915 dump_PMModelItemInfo(ndims);
917 else if (!strcmp(title, "NDimensional__DspCell"))
919 match_byte_assert(0);
928 static const int number_prefix[] = {
931 size_t number_prefix_len = sizeof number_prefix / sizeof *number_prefix;
932 if (match_bytes(pos, number_prefix, number_prefix_len))
937 printf ("%04x ", prev_end);
938 hex_dump (stdout, prev_end, pos - prev_end);
942 double d = *(double *) &data[pos + number_prefix_len];
943 printf ("float %f\n", d);
950 if (!memcmp (&data[pos + 4], "{\\rtf", 5))
952 int len = data[pos] + (data[pos + 1] << 8) + (data[pos + 2] << 16)
953 + (data[pos + 3] << 24);
954 if (len < n - pos - 4)
959 printf ("%04x ", prev_end);
960 hex_dump (stdout, prev_end, pos - prev_end);
971 if (data[pos] && data[pos + 1] && data[pos + 2] >= 0xfe
972 && data[pos + 3] == 0xff && data[pos + 4] && data[pos + 4] != 0xff)
977 printf ("%04x ", prev_end);
978 hex_dump (stdout, prev_end, pos - prev_end);
983 int32_t num = data[pos] + (data[pos + 1] << 8)
984 + (data[pos + 2] << 16) + (data[pos + 3] << 24);
985 printf ("%d (%+d) ", num, num - prev_num);
992 static const int font_prefix[] =
994 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x41, 0x72, 0x69, 0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
996 size_t font_prefix_len = sizeof font_prefix / sizeof *font_prefix;
997 if (match_bytes(pos, font_prefix, font_prefix_len))
1002 printf ("%04x ", prev_end);
1003 hex_dump (stdout, prev_end, pos - prev_end);
1009 pos += font_prefix_len;
1014 static const int string_prefix[] = {
1015 0x05, 0x80, 0x01, 0x02, 0x28, 0x05, 0x00, 0x01
1017 size_t string_prefix_len = sizeof string_prefix / sizeof *string_prefix;
1018 if (match_bytes(pos, string_prefix, string_prefix_len) && data[pos + string_prefix_len] != 255)
1020 if (prev_end != pos)
1023 printf ("%04x ", prev_end);
1024 hex_dump (stdout, prev_end, pos - prev_end);
1028 int len = data[pos + 8];
1029 printf ("string %.*s\n", len, &data[pos + 9]);
1034 if (match_bytes(pos, string_prefix, string_prefix_len) && data[pos + string_prefix_len] == 255)
1036 if (prev_end != pos)
1039 printf ("%04x ", prev_end);
1040 hex_dump (stdout, prev_end, pos - prev_end);
1044 int len = data[pos + 9] + (data[pos + 10] << 8);
1045 printf ("\nlongstring %.*s\n", len, &data[pos + 11]);
1054 if (!is_ascii(data[pos]))
1060 unsigned int start = pos;
1061 unsigned int end = pos + 1;
1062 while (is_ascii(data[end]))
1065 unsigned int len = end - start;
1072 unsigned int len2 = data[start - 2] + (data[start - 1] << 8);
1073 unsigned int len3 = data[start - 1];
1075 if (len2 && len2 <= len)
1080 else if (len3 && len3 <= len)
1097 unsigned real_start = start - length_bytes;
1098 if (prev_end != real_start)
1101 printf ("%04x ", prev_end);
1102 hex_dump (stdout, prev_end, real_start - prev_end);
1105 printf ("%04x ", real_start);
1106 printf ("\"%.*s\"\n",
1107 (int) end - start, (char *) &data[start]);