+static void
+parse_format(void)
+{
+ int d = data[pos++];
+ int w = data[pos++];
+ int fmt = data[pos++];
+ char buf[32];
+ printf ("%s%d.%d", format_name(fmt, buf), w, d);
+}
+
+static void
+parse_heading(const char *name)
+{
+ match_u16_assert(0xffff);
+ match_u16_assert(0);
+ match_string2_assert(name);
+}
+
+static void
+match_zeros_assert(int count, const char *where)
+{
+ for (int i = 0; i < count; i++)
+ if (data[pos + i])
+ {
+ fprintf (stderr,
+ "%s: %#x: expected %d zeros here but offset %d is %#"PRIx8"\n",
+ where, pos, count, i, data[pos + i]);
+ exit (1);
+ }
+ pos += count;
+}
+#define match_zeros_assert(count) match_zeros_assert(count, WHERE)
+
+static void
+put_safe(const char *s)
+{
+ while (*s)
+ {
+ if (*s == '\n')
+ printf ("\\n");
+ else if (*s == '\r')
+ printf ("\\r");
+ else if (*s < 0x20 || *s > 0x7e)
+ printf ("\\x%02"PRIx8, (uint8_t) *s);
+ else
+ putchar (*s);
+ s++;
+ }
+}
+
+static void
+parse_DspString(void)
+{
+ if (match_byte(2))
+ {
+ printf("DspString(%f, \"", get_double());
+ printf("%s\")\n", get_string1());
+ }
+ else
+ {
+ match_byte_assert(1);
+ printf ("DspString(");
+ parse_format();
+ printf(" \"");
+ match_byte_assert(0);
+ match_byte_assert(1);
+ put_safe(get_string1());
+ printf("\")\n");
+ }
+}
+
+static void
+match_DspString(void)
+{ /* 05 80 */
+ match_byte_assert(5);
+ match_byte_assert(0x80);
+ parse_DspString();
+}
+
+static void
+match_DspSimpleText(void)
+{ /* 03 80 */
+ match_byte_assert(3);
+ match_byte_assert(0x80);
+ match_zeros_assert(5);
+ if (!match_byte(0x10))
+ match_byte_assert(0);
+ match_zeros_assert(4);
+}
+
+static void
+match_NavTreeViewItem(void)
+{ /* 07 80 */
+ match_byte_assert(7);
+ match_byte_assert(0x80);
+ match_zeros_assert(1);
+ if (!match_byte(0) && !match_byte(7))
+ match_byte_assert(8);
+ match_zeros_assert(3);
+ pos++;
+ match_byte_assert(0);
+ match_byte_assert(1);
+ match_zeros_assert(3);
+ if (!match_byte(0))
+ match_byte_assert(1);
+ match_zeros_assert(5);
+ match_byte_assert(1);
+ match_zeros_assert(5);
+
+ put_safe(get_string1());
+ putc('\n', stdout);
+}
+
+static void
+parse_DspNumber(void)
+{
+ match_byte_assert(1);
+ printf("DspNumber(");
+ parse_format();
+ match_byte_assert(0x80);
+ match_byte(2);
+ printf (" %f", get_double());
+ printf (" \"%s\")\n", get_string1());
+}
+
+static void
+match_DspNumber(void)
+{
+ match_byte_assert(0x2a);
+ match_byte_assert(0x80);
+ parse_DspNumber();
+}
+
+static void parse_flexible(void);
+
+static void
+parse_DspCell(void)
+{
+ match_byte_assert(0);
+ match_DspSimpleText();
+ parse_flexible(); /* DspString or DspNumber. */
+}
+
+static void
+match_DspCell(void)
+{ /* 27 80 */
+ match_byte_assert(0x27);
+ match_byte_assert(0x80);
+ parse_DspCell();
+}
+
+static void
+parse_PMModelItemInfo(void)
+{ /* 54 80 */
+ match_byte_assert(0);
+ pos += 1; /* Counter */
+ match_zeros_assert(7);
+ pos += 3;
+ if (!match_byte(0))
+ match_byte_assert(0xe);
+ match_byte_assert(0);
+}
+
+static void
+match_PMModelItemInfo(void)
+{ /* 54 80 */
+ match_byte_assert(0x54);
+ match_byte_assert(0x80);
+ parse_PMModelItemInfo();
+ match_DspSimpleText();
+ match_DspString();
+}
+
+static void
+match_PMPivotItemTree(void)
+{ /* 52 80 */
+ match_byte_assert(0x52);
+ match_byte_assert(0x80);
+ match_byte_assert(0);
+ match_PMModelItemInfo();
+}
+
+static void
+parse_flexible(void)
+{
+ if (data[pos] == 0xff && data[pos + 1] == 0xff)
+ {
+ match_u16_assert(0xffff);
+ match_u16_assert(0);
+ char *heading = get_string2();
+ if (!strcmp(heading, "DspCell"))
+ parse_DspCell();
+ else if (!strcmp(heading, "DspNumber"))
+ parse_DspNumber();
+ else if (!strcmp(heading, "DspString"))
+ parse_DspString();
+ else
+ assert(0);
+ }
+ else if (data[pos] == 0x2a && data[pos + 1] == 0x80)
+ match_DspNumber();
+ else if (data[pos] == 0x27 && data[pos + 1] == 0x80)
+ match_DspCell();
+ else if (data[pos] == 0x5 && data[pos + 1] == 0x80)
+ match_DspString();
+ else if ((data[pos] == 0x3c || data[pos] == 0x39)
+ && data[pos + 1] == 0x80)
+ {
+ /* 3c 80 */
+ /* 39 80 */
+ pos += 2;
+ parse_format();
+/* match_byte_assert(0x01);
+ match_byte_assert(0x02);
+ match_byte_assert(0x0d); */
+ }
+ else if (data[pos] == 0x15 && data[pos + 1] == 0x80)
+ {
+ /* 15 80 */
+ data += 2;
+ match_byte_assert(2);
+ printf ("15 80(%f", get_double());
+ printf (" %s)\n", get_string1());
+ }
+ else
+ {
+ fprintf (stderr, "bad data cell 0x%02x at offset %x\n",
+ data[pos], pos);
+ hex_dump (stderr, pos, 64);
+ assert(0);
+ }
+}