some success with dissecting data and dimensions
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 2 Jan 2020 23:53:22 +0000 (23:53 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 2 Jan 2020 23:53:22 +0000 (23:53 +0000)
dump-spo.c
spo-notes

index 2a75bef6a928fd81d55b6fc2f948eb45b404e1ec..1ca9f0a03f3fda520956e510c9db883a84767d9c 100644 (file)
@@ -93,6 +93,15 @@ match_u32(uint32_t x)
   return false;
 }
 
+bool
+match_u16(uint16_t x)
+{
+  if (get_u16() == x)
+    return true;
+  pos -= 2;
+  return false;
+}
+
 static void
 match_u32_assert(uint32_t x, const char *where)
 {
@@ -105,6 +114,18 @@ match_u32_assert(uint32_t x, const char *where)
 }
 #define match_u32_assert(x) match_u32_assert(x, WHERE)
 
+static void
+match_u16_assert(uint16_t x, const char *where)
+{
+  unsigned int y = get_u16();
+  if (x != y)
+    {
+      fprintf(stderr, "%s: 0x%x: expected u16:%u, got u16:%u\n", where, pos - 2, x, y);
+      exit(1);
+    }
+}
+#define match_u16_assert(x) match_u16_assert(x, WHERE)
+
 static bool __attribute__((unused))
 match_u64(uint64_t x)
 {
@@ -203,6 +224,15 @@ is_ascii(uint8_t p)
   return (p >= ' ' && p < 127) || p == '\r' || p == '\n' || p == '\t';
 }
 
+static int
+count_zeros(const uint8_t *p)
+{
+  size_t n = 0;
+  while (p[n] == 0)
+    n++;
+  return n;
+}
+
 static bool __attribute__((unused))
 all_utf8(const char *p_, size_t len)
 {
@@ -218,6 +248,24 @@ all_utf8(const char *p_, size_t len)
   return true;
 }
 
+static char *
+get_string1(void)
+{
+  int len = data[pos++];
+  char *s = xmemdup0(&data[pos], len);
+  pos += len;
+  return s;
+}
+
+static char *
+get_string2(void)
+{
+  int len = data[pos] + data[pos + 1] * 256;
+  char *s = xmemdup0(&data[pos + 2], len);
+  pos += 2 + len;
+  return s;
+}
+
 static char *
 get_string(const char *where)
 {
@@ -304,190 +352,20 @@ char_dump(FILE *stream, int ofs, int n)
   putc('\n', stream);
 }
 
-static char *
-dump_counted_string(void)
-{
-  int inner_end = get_end();
-  if (pos == inner_end)
-    return NULL;
-
-  if (match_u32(5))
-    {
-      match_u32_assert(0);
-      match_byte_assert(0x58);
-    }
-  else
-    match_u32_assert(0);
-
-  char *s = NULL;
-  if (match_byte(0x31))
-    s = get_string();
-  else
-    match_byte_assert(0x58);
-  if (pos != inner_end)
-    {
-      fprintf(stderr, "inner end discrepancy\n");
-      exit(1);
-    }
-  return s;
-}
-
-static void
-dump_style(FILE *stream)
-{
-  if (match_byte(0x58))
-    return;
-
-  match_byte_assert(0x31);
-  if (get_bool())
-    printf (" bold=\"yes\"");
-  if (get_bool())
-    printf (" italic=\"yes\"");
-  if (get_bool())
-    printf (" underline=\"yes\"");
-  if (!get_bool())
-    printf (" show=\"no\"");
-  char *fg = get_string();     /* foreground */
-  char *bg = get_string();     /* background */
-  char *font = get_string();     /* font */
-  int size = get_byte() * (72. / 96.);
-  fprintf(stream, " fgcolor=\"%s\" bgcolor=\"%s\" font=\"%s\" size=\"%dpt\"",
-          fg, bg, font, size);
-}
-
-static void
-dump_style2(FILE *stream)
-{
-  if (match_byte(0x58))
-    return;
 
-  match_byte_assert(0x31);
-  uint32_t halign = get_u32();
-  printf (" halign=\"%s\"",
-          halign == 0 ? "center"
-          : halign == 2 ? "left"
-          : halign == 4 ? "right"
-          : halign == 6 ? "decimal"
-          : halign == 0xffffffad ? "mixed"
-          : "<error>");
-  int valign = get_u32();
-  printf (" valign=\"%s\"",
-          valign == 0 ? "center"
-          : valign == 1 ? "top"
-          : valign == 3 ? "bottom"
-          : "<error>");
-  printf (" offset=\"%gpt\"", get_double());
-  int l = get_u16();
-  int r = get_u16();
-  int t = get_u16();
-  int b = get_u16();
-  printf (" margins=\"%d %d %d %d\"", l, r, t, b);
-}
-
-static char *
-dump_nested_string(FILE *stream)
+static int
+compare_int(const void *a_, const void *b_)
 {
-  char *s = NULL;
-
-  match_byte_assert (0);
-  match_byte_assert (0);
-  int outer_end = get_end();
-  s = dump_counted_string();
-  if (s)
-    fprintf(stream, " \"%s\"", s);
-  dump_style(stream);
-  match_byte_assert(0x58);
-  if (pos != outer_end)
-    {
-      fprintf(stderr, "outer end discrepancy\n");
-      exit(1);
-    }
-
-  return s;
+  const int *a = a_;
+  const int *b = b_;
+  return *a < *b ? -1 : *a > *b;
 }
 
-static void
-dump_value_modifier(FILE *stream)
-{
-  if (match_byte (0x31))
-    {
-      if (match_u32 (0))
-        {
-          fprintf(stream, "<special0");
-          if (match_u32 (1))
-            {
-              /* Corpus frequencies:
-                 124 "a"
-                 12 "b"
-                 8 "a, b"
-
-                 The given text is appended to the cell in a subscript font.
-              */
-              fprintf(stream, " subscript=\"%s\"", get_string());
-            }
-          else
-            match_u32_assert (0);
-
-          if (version == 1)
-            {
-              /* We only have one SPV file for this version (with many
-                 tables). */
-              match_byte(0);
-              if (!match_u32(1))
-                match_u32_assert(2);
-              match_byte(0);
-              match_byte(0);
-              if (!match_u32(0) && !match_u32(1) && !match_u32(2) && !match_u32(3) && !match_u32(4) && !match_u32(5) && !match_u32(6) && !match_u32(7) && !match_u32(8) && !match_u32(9))
-                match_u32_assert(10);
-              match_byte(0);
-              match_byte(0);
-              fprintf(stream, "/>\n");
-              return;
-            }
-
-          int outer_end = get_end();
-          
-          /* This counted-string appears to be a template string,
-             e.g. "Design\: [:^1:]1 Within Subjects Design\: [:^1:]2". */
-          char *template = dump_counted_string();
-          if (template)
-            fprintf(stream, " template=\"%s\"", template);
-
-          dump_style(stream);
-          dump_style2(stream);
-          if (pos != outer_end)
-            {
-              fprintf(stderr, "outer end discrepancy\n");
-              exit(1);
-            }
-          fprintf(stream, "/>\n");
-        }
-      else
-        {
-          int count = get_u32();
-          fprintf(stream, "<footnote-ref indexes=\"");
-          for (int i = 0; i < count; i++)
-            {
-              if (i)
-                putc(' ', stream);
-              fprintf(stream, "%d", get_u16());
-            }
-          putc('"', stream);
-          match_byte_assert(0);
-          match_byte_assert(0);
-          dump_nested_string(stream);
-          fprintf(stream, "/>\n");
-        }
-    }
-  else
-    match_byte_assert (0x58);
-}
 
 static const char *
-format_to_string (int type)
+format_name (int format, char *buf)
 {
-  static char tmp[16];
-  switch (type)
+  switch (format)
     {
     case 1: return "A";
     case 2: return "AHEX";
@@ -524,797 +402,265 @@ format_to_string (int type)
     case 37: return "CCE";
     case 38: return "EDATE";
     case 39: return "SDATE";
-    default:
-      assert(false);
-      sprintf(tmp, "<%d>", type);
-      return tmp;
+    default: sprintf(buf, "(%d)", format); return buf;
     }
 }
 
 static void
-dump_value(FILE *stream, int level)
+dump_DspNumber(void)
 {
-  match_byte(0);
-  match_byte(0);
-  match_byte(0);
-  match_byte(0);
+  match_byte_assert(1);
+  int d = get_byte();
+  int w = get_byte();
+  int fmt = get_byte();
+  char buf[64];
+  printf ("%s%d.%d ", format_name (fmt, buf), w, d);
 
-  for (int i = 0; i <= level; i++)
-    fprintf (stream, "    ");
+  match_byte_assert(0x80);
+  match_byte_assert(2);
+  printf ("%f ", get_double ());
+  printf ("\"%s\"\n", get_string1 ());
 
-  printf ("%02x: value (%d)\n", pos, data[pos]);
-  if (match_byte (1))
-    {
-      unsigned int format;
-      double value;
-
-      dump_value_modifier(stream);
-      format = get_u32 ();
-      value = get_double ();
-      fprintf (stream, "<number value=\"%.*g\" format=\"%s%d.%d\"/>\n",
-               DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
-    }
-  else if (match_byte (2))
-    {
-      unsigned int format;
-      char *var, *vallab;
-      double value;
-
-      dump_value_modifier (stream);
-      format = get_u32 ();
-      value = get_double ();
-      var = get_string ();
-      vallab = get_string ();
-      fprintf (stream, "<numeric-datum value=\"%.*g\" format=\"%s%d.%d\"",
-              DBL_DIG, value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
-      if (var[0])
-        fprintf (stream, " variable=\"%s\"", var);
-      if (vallab[0])
-        fprintf (stream, " label=\"%s\"", vallab);
-      fprintf (stream, "/>\n");
-      if (!match_byte (1) && !match_byte(2))
-        match_byte_assert (3);
-    }
-  else if (match_byte (3))
-    {
-      char *text =  get_string();
-      dump_value_modifier(stream);
-      char *identifier = get_string();
-      char *text_eng = get_string();
-      fprintf (stream, "<string c=\"%s\"", text_eng);
-      if (identifier[0])
-        fprintf (stream, " identifier=\"%s\"", identifier);
-      if (strcmp(text_eng, text))
-        fprintf (stream, " local=\"%s\"", text);
-      fprintf (stream, "/>\n");
-      if (!match_byte (0))
-        match_byte_assert(1);
-    }
-  else if (match_byte (4))
-    {
-      unsigned int format;
-      char *var, *vallab, *value;
-
-      dump_value_modifier(stream);
-      format = get_u32 ();
-      vallab = get_string ();
-      var = get_string ();
-      if (!match_byte(1) && !match_byte(2))
-        match_byte_assert (3);
-      value = get_string ();
-      fprintf (stream, "<string-datum value=\"%s\" format=\"%s%d.%d\"",
-              value, format_to_string(format >> 16), (format >> 8) & 0xff, format & 0xff);
-      if (var[0])
-        fprintf (stream, " variable=\"%s\"", var);
-      if (vallab[0])
-        fprintf (stream, " label=\"%s\"/>\n", vallab);
-      fprintf (stream, "/>\n");
-    }
-  else if (match_byte (5))
-    {
-      dump_value_modifier(stream);
-      char *name = get_string ();
-      char *label = get_string ();
-      fprintf (stream, "<variable name=\"%s\"", name);
-      if (label[0])
-        fprintf (stream, " label=\"%s\"", label);
-      fprintf (stream, "/>\n");
-      if (!match_byte(1) && !match_byte(2))
-        match_byte_assert(3);
-    }
-  else
+  for (;;)
     {
-      printf ("else %#x\n", pos);
-      dump_value_modifier(stream);
-
-      char *base = get_string();
-      int x = get_u32();
-      fprintf (stream, "<template format=\"%s\">\n", base);
-      for (int i = 0; i < x; i++)
+      if (data[pos] == 0xff)
         {
-          int y = get_u32();
-          if (!y)
-            y = 1;
-          else
-            match_u32_assert(0);
-          for (int j = 0; j <= level + 1; j++)
-            fprintf (stream, "    ");
-          fprintf (stream, "<substitution index=\"%d\">\n", i + 1);
-          for (int j = 0; j < y; j++)
-            dump_value (stream, level + 2);
-          for (int j = 0; j <= level + 1; j++)
-            fprintf (stream, "    ");
-          fprintf (stream, "</substitution>\n");
+          printf ("\nff exit");
+          break;
         }
-      for (int j = 0; j <= level; j++)
-        fprintf (stream, "    ");
-      fprintf (stream, "</template>\n");
-    }
-}
 
-static int
-compare_int(const void *a_, const void *b_)
-{
-  const int *a = a_;
-  const int *b = b_;
-  return *a < *b ? -1 : *a > *b;
-}
-
-static void
-check_permutation(int *a, int n, const char *name)
-{
-  int b[n];
-  memcpy(b, a, n * sizeof *a);
-  qsort(b, n, sizeof *b, compare_int);
-  for (int i = 0; i < n; i++)
-    if (b[i] != i)
-      {
-        fprintf(stderr, "bad %s permutation:", name);
-        for (int i = 0; i < n; i++)
-          fprintf(stderr, " %d", a[i]);
-        putc('\n', stderr);
-        exit(1);
-      }
-}
-
-static void
-dump_category(FILE *stream, int level, int **indexes, int *allocated_indexes,
-              int *n_indexes)
-{
-  for (int i = 0; i <= level; i++)
-    fprintf (stream, "    ");
-  printf ("<category>\n");
-  dump_value (stream, level + 1);
-
-  bool merge = get_bool();
-  match_byte_assert (0);
-  int unindexed = get_bool();
-
-  int x = get_u32 ();
-  pos -= 4;
-  if (!match_u32 (0))
-    match_u32_assert (2);
-
-  int indx = get_u32();
-  int n_categories = get_u32();
-  if (indx == -1)
-    {
-      if (merge)
+      if (data[pos] == 0x80 && data[pos + 1] == 1)
         {
-          for (int i = 0; i <= level + 1; i++)
-            fprintf (stream, "    ");
-          fprintf (stream, "<merge/>\n");
+          pos += 2;
+          int d = get_byte();
+          int w = get_byte();
+          int fmt = get_byte();
+          char buf[64];
+          printf ("\n%% %s%d.%d\n", format_name (fmt, buf), w, d);
         }
-      assert (unindexed);
-    }
-  else
-    {
-      assert (!merge);
-      assert (!unindexed);
-      assert (x == 2);
-      assert (n_categories == 0);
-      if (*n_indexes >= *allocated_indexes)
+      else if (data[pos] == 0x80 && data[pos + 1] == 2)
         {
-          *allocated_indexes = *allocated_indexes ? 2 * *allocated_indexes : 16;
-          *indexes = realloc(*indexes, *allocated_indexes * sizeof **indexes);
+          pos += 2;
+          printf ("\n%f ", get_double ());
+          printf ("'%s'\n", get_string1 ());
         }
-      (*indexes)[(*n_indexes)++] = indx;
-    }
-
-  if (n_categories == 0)
-    {
-      for (int i = 0; i <= level + 1; i++)
-        fprintf (stream, "    ");
-      fprintf (stream, "<category-index>%d</category-index>\n", indx);
-    }
-  for (int i = 0; i < n_categories; i++)
-    dump_category (stream, level + 1, indexes, allocated_indexes, n_indexes);
-  for (int i = 0; i <= level; i++)
-    fprintf (stream, "    ");
-  printf ("</category>\n");
-}
-
-static int
-dump_dim(int indx)
-{
-  int n_categories;
-
-  printf ("<dimension index=\"%d\">\n", indx);
-  dump_value (stdout, 0);
-
-  /* This byte is usually 0 but many other values have been spotted.
-     No visible effect. */
-  pos++;
-
-  /* This byte can cause data to be oddly replicated. */
-  if (!match_byte(0) && !match_byte(1))
-    match_byte_assert(2);
-
-  if (!match_u32(0))
-    match_u32_assert(2);
-
-  bool show_dim_label = get_bool();
-  if (show_dim_label)
-    printf("  <show-dim-label/>\n");
-
-  bool hide_all_labels = get_bool();
-  if (hide_all_labels)
-    printf("  <hide-all-labels/>\n");
-
-  match_byte_assert(1);
-  if (!match_u32(UINT32_MAX))
-    match_u32_assert(indx);
-
-  n_categories = get_u32();
-
-  int *indexes = NULL;
-  int n_indexes = 0;
-  int allocated_indexes = 0;
-  for (int i = 0; i < n_categories; i++)
-    dump_category (stdout, 0, &indexes, &allocated_indexes, &n_indexes);
-  check_permutation(indexes, n_indexes, "categories");
-
-  fprintf (stdout, "</dimension>\n");
-  return n_indexes;
-}
-
-int n_dims;
-static int dim_n_cats[64];
-#define MAX_DIMS (sizeof dim_n_cats / sizeof *dim_n_cats)
-
-static void
-dump_dims(void)
-{
-  n_dims = get_u32();
-  assert(n_dims < MAX_DIMS);
-  for (int i = 0; i < n_dims; i++)
-    dim_n_cats[i] = dump_dim (i);
-}
-
-static void
-dump_data(void)
-{
-  /* The first three numbers add to the number of dimensions. */
-  int l = get_u32();
-  int r = get_u32();
-  int c = n_dims - l - r;
-  match_u32_assert(c);
-
-  /* The next n_dims numbers are a permutation of the dimension numbers. */
-  int a[n_dims];
-  for (int i = 0; i < n_dims; i++)
-    {
-      int dim = get_u32();
-      a[i] = dim;
-
-      const char *name = i < l ? "layer" : i < l + r ? "row" : "column";
-      printf ("<%s dimension=\"%d\"/>\n", name, dim);
-    }
-  check_permutation(a, n_dims, "dimensions");
-
-  int x = get_u32();
-  printf ("<data>\n");
-  for (int i = 0; i < x; i++)
-    {
-      unsigned int indx = get_u32();
-      printf ("    <datum index=\"%d\" coords=", indx);
-
-      int coords[MAX_DIMS];
-      for (int i = n_dims; i-- > 0; )
+      else if (data[pos] == 0x80 && data[pos + 1] == 0 && data[pos + 2] == 3)
+        pos += 3;
+      else if (data[pos] == 0x80 && count_zeros(&data[pos + 1]) == 10)
+        pos += 11;
+      else if (data[pos] == 0x1 && data[pos + 1] == 0xff)
         {
-          coords[i] = indx % dim_n_cats[i];
-          indx /= dim_n_cats[i];
+          pos += 2;
+          printf ("\n\"%s\"\n", get_string2 ());
         }
-      for (int i = 0; i < n_dims; i++)
-        printf("%c%d", i ? ',' : '"', coords[i]);
-
-      printf ("\">\n");
-      match_u32_assert(0);
-      if (version == 1)
-        match_byte(0);
-      dump_value(stdout, 1);
-      fprintf (stdout, "    </datum>\n");
+      else if (data[pos] == 0x1 && data[pos + 1])
+        {
+          pos += 1;
+          printf ("\n\"%s\"\n", get_string1 ());
+        }
+      else
+        printf ("%02x ", get_byte());
     }
-  printf ("</data>\n");
 }
 
 static void
-dump_title(void)
+dump_cell(void)
 {
-  printf ("<title-local>\n");
-  dump_value(stdout, 0);
-  match_byte(1);
-  printf ("</title-local>\n");
-
-  printf ("<subtype>\n");
-  dump_value(stdout, 0);
-  match_byte(1);
-  printf ("</subtype>\n");
-
-  match_byte_assert(0x31);
-
-  printf ("<title-c>\n");
-  dump_value(stdout, 0);
-  match_byte(1);
-  printf ("</title-c>\n");
-
-  if (match_byte(0x31))
-    {
-      printf ("<user-caption>\n");
-      dump_value(stdout, 0);
-      printf ("</user-caption>\n");
-    }
-  else
-    match_byte_assert(0x58);
-  if (match_byte(0x31))
+  static const int cell_prefix[] = {
+    0x00, 0x03, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, -1 /* 00 or 10 */, 0x00, 0x00, 0x00, 0x00,
+
+    /*13  14    15  16  17  18  19 */
+    -1, 0x80, 0x01, -1, -1, -1, -1,
+  };
+  size_t cell_prefix_len = sizeof cell_prefix / sizeof *cell_prefix;
+  if (!match_bytes(pos, cell_prefix, cell_prefix_len))
     {
-      printf ("<caption>\n");
-      dump_value(stdout, 0);
-      printf ("</caption>\n");
+      printf ("match failed at %x\n", pos);
+      return;
     }
-  else
-    match_byte_assert(0x58);
 
-  int n_footnotes = get_u32();
-  for (int i = 0; i < n_footnotes; i++)
+  char buf[64];
+  printf ("cell %s%d.%d ",
+          format_name (data[pos + 18], buf),
+          data[pos + 17],
+          data[pos + 16]);
+
+  int len = cell_prefix_len;
+  if (data[pos + 19] == 0)
     {
-      printf ("<footnote index=\"%d\">\n", i);
-      dump_value(stdout, 0);
-      /* Custom footnote marker string. */
-      if (match_byte (0x31))
-        dump_value(stdout, 0);
-      else
-        match_byte_assert (0x58);
-      int n = get_u32();
-      if (n >= 0)
+      assert (data[pos + 13] == 5);
+      if (data[pos + 20] == 0)
+        {
+          int count = (data[pos + 22]);
+          printf ("%d %d \"%.*s\"",
+                  data[pos + 21], data[pos + 22],
+                  count, &data[pos + 23]);
+          len = 23 + count;
+        }
+      else if (data[pos + 20] == 1
+               && data[pos + 21] == 0xff
+               && data[pos + 22] == 0xff)
+        {
+          int count = 255;
+          printf ("%d \"%.*s\"", count, data[pos + 23],
+                  &data[pos + 24]);
+          len = 23 + count;
+        }
+      else if (data[pos + 20] == 1 && data[pos + 21] == 255)
         {
-          /* Appears to be the number of references to a footnote. */
-          printf ("  <references n=\"%d\"/>\n", n);
+          int count = data[pos + 22] + (data[pos + 23] << 8);
+          printf ("\"%.*s\"",
+                  count, &data[pos + 24]);
+          len = 24 + count;
         }
-      else if (n == -2)
+      else if (data[pos + 20] == 1)
         {
-          /* The user deleted the footnote references. */
-          printf ("  <deleted/>\n");
+          int count = (data[pos + 21]);
+          printf ("\"%.*s\"",
+                  count, &data[pos + 22]);
+          len = 22 + count;
         }
       else
-        assert(0);
-      printf ("</footnote>\n");
+        assert (false);
     }
-}
-
-static void
-dump_fonts(void)
-{
-  match_byte(0);
-  for (int i = 1; i <= 8; i++)
+  else if (data[pos + 19] == 128 && data[pos + 20] == 2)
     {
-      printf ("<style index=\"%d\"", i);
-      match_byte_assert(i);
-      match_byte_assert(0x31);
-      printf(" font=\"%s\"", get_string());
-
-      printf(" size=\"%gpt\"", get_float());
-
-      int style = get_u32();
-      if (style & 1)
-        printf(" bold=\"true\"");
-      if (style & 2)
-        printf(" italic=\"true\"");
-
-      bool underline = data[pos++];
-      if (underline)
-        printf(" underline=\"true\"");
-
-      int halign = get_u32();
-      printf(" halign=%d", halign);
-
-      int valign = get_u32();
-      printf(" valign=%d", valign);
-
-      printf (" fgcolor=\"%s\"", get_string());
-      printf (" bgcolor=\"%s\"", get_string());
-
-      if (!match_byte(0))
-        match_byte_assert(1);
-
-      char *alt_fgcolor = get_string();
-      if (alt_fgcolor[0])
-        printf (" altfg=\"%s\"", alt_fgcolor);
-      char *alt_bgcolor = get_string();
-      if (alt_bgcolor[0])
-        printf (" altbg=\"%s\"", alt_bgcolor);
-
-      if (version > 1)
+      /* pos + 13 is usually 22...53, and it's 3 more than the
+         " xx 80" separator between cells  */
+      printf ("xxx%x ", data[pos + 13]);
+      double d = *(double *) &data[pos + 21];
+      len = 29;
+      const union
         {
-          printf(" margins=\"");
-          for (int i = 0; i < 4; i++)
-            {
-              if (i)
-                putchar(' ');
-              printf("%d", get_u32());
-            }
-          putchar('"');
+          uint8_t b[8];
+          double d;
         }
+      sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
+      if (d == sysmis.d)
+        printf ("sysmis");
+      else
+        printf ("%f", d);
 
-      printf ("/>\n");
-    }
-
-  int x1 = get_u32();
-  int x1_end = pos + x1;
-  printf("<borders>\n");
-  match_be32_assert(1);
-  int n_borders = get_be32();
-  for (int i = 0; i < n_borders; i++)
-    {
-      int type = get_be32();
-      int stroke = get_be32();
-      int color = get_be32();
-      printf("  <border type=\"%d\" stroke=\"%s\" color=\"#%06x\"/>\n",
-             type,
-             (stroke == 0 ? "none"
-              : stroke == 1 ? "solid"
-              : stroke == 2 ? "dashed"
-              : stroke == 3 ? "thick"
-              : stroke == 4 ? "thin"
-              : stroke == 5 ? "double"
-              : "<error>"),
-             color);
-    }
-  bool grid = get_byte();
-  pos += 3;
-  printf("  <grid show=\"%s\"/>\n", grid ? "yes" : "no");
-  printf("</borders>\n");
-  assert(pos == x1_end);
-
-  int skip = get_u32();
-  assert(skip == 18 || skip == 25);
-  pos += skip;
-
-  int x3 = get_u32();
-  int x3_end = pos + x3;
-  if (version == 3)
-    {
-      match_be32_assert(1);
-      get_be32();
-      printf("<settings layer=\"%d\"", get_be32());
-      if (!get_bool())
-        printf(" skipempty=\"false\"");
-      if (!get_bool())
-        printf(" showdimensionincorner=\"false\"");
-      if (!get_bool())
-        printf(" markers=\"numeric\"");
-      if (!get_bool())
-        printf(" footnoteposition=\"subscript\"");
-      get_byte();
-      int nbytes = get_be32();
-      int end = pos + nbytes;
-      printf("\n");
-      while (pos + 4 <= end)
-        printf(" %d", get_be32());
-      pos = end;
-      printf("\n");
-      pos += nbytes;
-      char *notes = get_string_be();
-      if (notes[0])
-        printf(" notes=\"%s\"", notes);
-      char *look = get_string_be();
-      if (look[0])
-        printf(" look=\"%s\"", look);
-      printf(">\n");
-    }
-  pos = x3_end;
-
-  /* Manual column widths, if present. */
-  int count = get_u32();
-  if (count > 0)
-    {
-      printf("<columnwidths>");
-      for (int i = 0; i < count; i++)
+      if (data[pos + 29] < 0xff
+          && all_utf8((char *) &data[pos + 30], data[pos + 29]))
         {
-          if (i)
-            putchar(' ');
-          printf("%d", get_u32());
+          printf (" \"%.*s\"", (int) data[pos + 29],
+                  &data[pos + 30]);
+          len += data[pos + 29] + 1;
         }
-      printf("</columnwidths>\n");
+      else
+        assert (false);
     }
-
-  const char *locale = get_string();
-  printf ("<locale>%s</locale>\n", locale);
-
-  printf ("<layer>%d</layer>\n", get_u32());
-  if (!match_byte(0))
-    match_byte_assert(1);
-  if (!match_byte(0))
-    match_byte_assert(1);
-  if (!match_byte(0))
-    match_byte_assert(1);
-  printf("<epoch>%d</epoch>\n", get_u32());
-
-  int decimal = data[pos];
-  int grouping = data[pos + 1];
-  if (match_byte('.'))
+  else if (data[pos + 19] == 128 && data[pos + 20] == 1 &&
+           data[pos + 21] == 0)
     {
-      if (!match_byte(',') && !match_byte('\''))
-        match_byte_assert(' ');
+      if (data[pos + 23] < 0xff
+          && all_utf8((char *) &data[pos + 24], data[pos + 23]))
+        {
+          printf (" \"%.*s\"", (int) data[pos + 23],
+                  &data[pos + 24]);
+          len = 24 + data[pos + 23];
+        }
+      else
+        assert (false);
     }
   else
     {
-      match_byte_assert(',');
-      if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
-        match_byte_assert(0);
-    }
-  printf("<format decimal=\"%c\"", decimal);
-  if (grouping)
-    printf(" grouping=\"%c\"", grouping);
-  printf("\"/>\n");
-  if (match_u32(5))
-    {
-      for (int i = 0; i < 5; i++)
-        printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
+      printf ("xxx%d %d %d %d",
+              data[pos + 19], data[pos + 20],
+              data[pos + 21], data[pos + 22]);
+      assert(false);
     }
-  else
-    match_u32_assert(0);
-
-  /* The last chunk is an outer envelope that contains two inner envelopes.
-     The second inner envelope has some interesting data like the encoding and
-     the locale. */
-  int outer_end = get_end();
-  if (version == 3)
-    {
-      /* First inner envelope: byte*33 int[n] int*[n]. */
-      int inner_len = get_u32();
-      int inner_end = pos + inner_len;
-      int array_start = pos + 33;
-      match_byte_assert(0);
-      pos++;                    /* 0, 1, 10 seen. */
-      get_bool();
-
-      /* 0=en 1=de 2=es 3=it 5=ko 6=pl 8=zh-tw 10=pt_BR 11=fr */
-      printf("lang=%d ", get_byte());
-
-      printf ("variable_mode=%d\n", get_byte());
-      printf ("value_mode=%d\n", get_byte());
-      if (!match_u64(0))
-        match_u64_assert(UINT64_MAX);
-      match_u32_assert(0);
-      match_u32_assert(0);
-      match_u32_assert(0);
-      match_u32_assert(0);
-      match_byte_assert(0);
-      get_bool();
-      match_byte_assert(1);
-      pos = array_start;
-
-      assert(get_end() == inner_end);
-      printf("<heights>");
-      int n_heights = get_u32();
-      for (int i = 0; i < n_heights; i++)
-        {
-          if (i)
-            putchar(' ');
-          printf("%d", get_u32());
-        }
-      printf("</heights>\n");
-
-      int n_style_map = get_u32();
-      for (int i = 0; i < n_style_map; i++)
-        {
-          uint64_t cell = get_u64();
-          int style = get_u16();
-          printf("<style-map cell=\"%lu\" style=\"%d\"/>\n", cell, style);
-        }
-
-      int n_styles = get_u32();
-      for (int i = 0; i < n_styles; i++)
-        {
-          printf("<cell-style index=\"%d\"", i);
-          dump_style(stdout);
-          dump_style2(stdout);
-          printf("/>\n");
-        }
-
-      pos = get_end();
-      assert(pos == inner_end);
-
-      /* Second inner envelope. */
-      assert(get_end() == outer_end);
-
-      match_byte_assert(1);
-      match_byte_assert(0);
-      if (!match_byte(3) && !match_byte(4))
-        match_byte_assert(5);
-      match_byte_assert(0);
-      match_byte_assert(0);
-      match_byte_assert(0);
+  pos += len;
+}
 
-      printf("<command>%s</command>\n", get_string());
-      printf("<command-local>%s</command-local>\n", get_string());
-      printf("<language>%s</language>\n", get_string());
-      printf("<charset>%s</charset>\n", get_string());
-      printf("<locale>%s</locale>\n", get_string());
+static void
+dump_category (int level, uint8_t *catstart, bool *have_catstart)
+{
+  int cat_index = get_u32();
+  assert (cat_index < 256);
 
-      get_bool();
-      get_bool();
-      get_bool();
-      get_bool();
+  if (!match_u32 (0))
+    match_u32_assert (1);
 
-      printf("<epoch2>%d</epoch2>\n", get_u32());
+  get_u16();
 
-      if (match_byte('.'))
-        {
-          if (!match_byte(',') && !match_byte('\''))
-            match_byte_assert(' ');
-        }
-      else
-        {
-          match_byte_assert(',');
-          if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
-            match_byte_assert(0);
-        }
+  if (!match_u16(0xe74) && !match_u16(0xffff))
+    match_u16_assert(0);
 
-      printf ("small: %g\n", get_double());
+  for (int i = 0; i < level; i++)
+    printf ("  ");
 
-      match_byte_assert(1);
-      if (outer_end - pos > 6)
-        {
-          /* There might be a pair of strings representing a dataset and
-             datafile name, or there might be a set of custom currency strings.
-             The custom currency strings start with a pair of integers, so we
-             can distinguish these from a string by checking for a null byte; a
-             small 32-bit integer will always contain a null and a text string
-             never will. */
-          int save_pos = pos;
-          int len = get_u32();
-          bool has_dataset = !memchr(&data[pos], '\0', len);
-          pos = save_pos;
-
-          if (has_dataset)
-            {
-              printf("<dataset>%s</dataset>\n", get_string());
-              printf("<datafile>%s</datafile>\n", get_string());
+  for (int i = 0; ; i++, pos++)
+    if (data[pos] == 5 && data[pos + 1] == 0x80)
+      break;
+    else if (i >= 100)
+      assert(false);
 
-              match_u32_assert(0);
+  match_byte_assert (5);
+  match_byte_assert (0x80);
+  if (match_byte(2))
+    get_double ();
+  else
+    {
+      match_byte_assert (1);
+      match_byte_assert (2);
+      match_byte_assert (0x28);
+      match_byte_assert (5);
+      match_byte_assert (0);
+      match_byte_assert (1);
+    }
+  printf (" \"%s\"", get_string1());
 
-              time_t date = get_u32();
-              struct tm tm = *localtime(&date);
-              char s[128];
-              strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S %z", &tm);
-              printf("<date>%s</date>\n", s);
+  int n_children = get_u32();
+  assert (n_children < 256);
+  if (n_children)
+    printf (" (group with %d children)", n_children);
+  else
+    printf (" (category #%d)", cat_index);
 
-              match_u32_assert(0);
-            }
-        }
+  printf (" %02x %02x %02x %02x %02x %02x\n",
+          data[pos], data[pos + 1], data[pos + 2],
+          data[pos + 3], data[pos + 4], data[pos + 5]);
+  if (!*have_catstart)
+    {
+      *have_catstart = true;
+      memcpy(catstart, &data[pos], 6);
+    }
+  pos += 6;
 
-      if (match_u32(5))
-        {
-          for (int i = 0; i < 5; i++)
-            printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
-        }
-      else
-        match_u32_assert(0);
+  for (int i = 0; i < n_children; i++)
+    dump_category (level + 1, catstart, have_catstart);
+}
 
-      match_byte_assert('.');
-      get_bool();
+static void
+dump_PMModelItemInfo(int ndims)
+{
+  return;
+#if 0
+  if (data[pos + 9] && data[pos + 9] != 0xff)//count_zeros (&data[pos + 9]) < 4)
+    return;
+#endif
+  
+  match_byte_assert (0);
 
-      if (pos < outer_end)
-        {
-          get_u32();
-          match_u32_assert(0);
-        }
-      assert(pos == outer_end);
+  uint8_t catstart[6];
+  bool have_catstart = false;
+  dump_category (0, catstart, &have_catstart);
+  assert(have_catstart);
 
-      pos = outer_end;
-    }
-  else if (outer_end != pos)
+  for (int i = 1; i < ndims; i++)
     {
-      pos += 14;
-      printf("<command>%s</command>\n", get_string());
-      printf("<command-local>%s</command-local>\n", get_string());
-      printf("<language>%s</command>\n", get_string());
-      printf("<charset>%s</charset>\n", get_string());
-      printf("<locale>%s</locale>\n", get_string());
-      get_bool();
-      match_byte_assert(0);
-      get_bool();
-      get_bool();
-
-      printf("<epoch2>%d</epoch2>\n", get_u32());
-      int decimal = data[pos];
-      int grouping = data[pos + 1];
-      if (match_byte('.'))
+      for (int j = 0; ; j++, pos++)
         {
-          if (!match_byte(',') && !match_byte('\''))
-            match_byte_assert(' ');
+          assert (j <= 1000);
+          if (!memcmp(&data[pos], catstart, 6))
+            break;
         }
-      else
-        {
-          match_byte_assert(',');
-          if (!match_byte('.') && !match_byte(' ') && !match_byte(','))
-            match_byte_assert(0);
-        }
-      printf("<format decimal=\"%c\"", decimal);
-      if (grouping)
-        printf(" grouping=\"%c\"", grouping);
-      printf("\"/>\n");
-      if (match_u32(5))
-        {
-          for (int i = 0; i < 5; i++)
-            printf("<CC%c>%s</CC%c>\n", 'A' + i, get_string(), 'A' + i);
-        }
-      else
-        match_u32_assert(0);
+      pos += 6;
 
-      match_byte_assert('.');
-      get_bool();
-
-      assert(pos == outer_end);
-      pos = outer_end;
-    }
-}
-
-static const char *
-format_name (int format, char *buf)
-{
-  switch (format)
-    {
-    case 1: return "A";
-    case 2: return "AHEX";
-    case 3: return "COMMA";
-    case 4: return "DOLLAR";
-    case 5: return "F";
-    case 6: return "IB";
-    case 7: return "PIBHEX";
-    case 8: return "P";
-    case 9: return "PIB";
-    case 10: return "PK";
-    case 11: return "RB";
-    case 12: return "RBHEX";
-    case 15: return "Z";
-    case 16: return "N";
-    case 17: return "E";
-    case 20: return "DATE";
-    case 21: return "TIME";
-    case 22: return "DATETIME";
-    case 23: return "ADATE";
-    case 24: return "JDATE";
-    case 25: return "DTIME";
-    case 26: return "WKDAY";
-    case 27: return "MONTH";
-    case 28: return "MOYR";
-    case 29: return "QYR";
-    case 30: return "WKYR";
-    case 31: return "PCT";
-    case 32: return "DOT";
-    case 33: return "CCA";
-    case 34: return "CCB";
-    case 35: return "CCC";
-    case 36: return "CCD";
-    case 37: return "CCE";
-    case 38: return "EDATE";
-    case 39: return "SDATE";
-    case 40: return "MTIME";
-    case 41: return "YMDHMS";
-    default: sprintf(buf, "(%d)", format); return buf;
+      dump_category (0, catstart, &have_catstart);
     }
 }
 
@@ -1416,7 +762,8 @@ main(int argc, char *argv[])
 #endif
   unsigned int prev_end = 0;
   char *title = "";
-  for (pos = 2; pos + 50 < n; pos++)
+  int ndims = 0;
+  for (pos = 2; pos + 50 < n; )
     {
       static const int cell_prefix[] = {
         0x00, 0x03,
@@ -1433,16 +780,6 @@ main(int argc, char *argv[])
               if (print_offsets)
                 printf ("%04x ", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
-
-              if (!strcmp (title, "DspNumber")
-                  && pos - prev_end == 2
-                  && data[prev_end + 1] == 0x80)
-                {
-                  static int already = false;
-                  if (!already)
-                    fprintf (stderr, " sum=%d %02x\n", sum, data[prev_end]);
-                  already = true;
-                }
             }
 
           char buf[64];
@@ -1472,6 +809,13 @@ main(int argc, char *argv[])
                           &data[pos + 24]);
                   len = 23 + count;
                 }
+              else if (data[pos + 20] == 1 && data[pos + 21] == 255)
+                {
+                  int count = data[pos + 22] + (data[pos + 23] << 8);
+                  printf ("\"%.*s\"\n",
+                          count, &data[pos + 24]);
+                  len = 24 + count;
+                }
               else if (data[pos + 20] == 1)
                 {
                   int count = (data[pos + 21]);
@@ -1532,8 +876,8 @@ main(int argc, char *argv[])
                       data[pos + 21], data[pos + 22]);
               assert(false);
             }
-          pos += len - 1;
-          prev_end = pos + 1;
+          pos += len;
+          prev_end = pos;
           continue;
         }
 
@@ -1559,11 +903,24 @@ main(int argc, char *argv[])
               printf ("rec:%-20.*s ", slen, &data[pos + 6]);
               len = slen + 6;
               title = xmemdup0(&data[pos + 6], slen);
-              fprintf (stderr, "%s%d ", title, data[pos + len]);
               sum += data[pos+len];
 
-              pos += len - 1;
-              prev_end = pos + 1;
+              pos += len;
+
+              if (!strcmp(title, "DspNumber"))
+                dump_DspNumber();
+              else if (!strcmp(title, "PMModelItemInfo"))
+                {
+                  assert(ndims);
+                  dump_PMModelItemInfo(ndims);
+                }
+              else if (!strcmp(title, "NDimensional__DspCell"))
+                {
+                  match_byte_assert(0);
+                  ndims = get_u32();
+                  assert(ndims < 10);
+                }
+              prev_end = pos;
               continue;
             }
         }
@@ -1585,8 +942,8 @@ main(int argc, char *argv[])
           double d = *(double *) &data[pos + number_prefix_len];
           printf ("float %f\n", d);
 
-          pos += 10 - 1;
-          prev_end = pos + 1;
+          pos += 10;
+          prev_end = pos;
           continue;
         }
 
@@ -1605,8 +962,8 @@ main(int argc, char *argv[])
               prev_end = pos;
 
               printf ("rtf\n");
-              pos += 4 + len - 1;
-              prev_end = pos + 1;
+              pos += 4 + len;
+              prev_end = pos;
               continue;
             }
         }
@@ -1627,8 +984,8 @@ main(int argc, char *argv[])
             + (data[pos + 2] << 16) + (data[pos + 3] << 24);
           printf ("%d (%+d) ", num, num - prev_num);
           prev_num = num;
-          pos += 4 - 1;
-          prev_end = pos + 1;
+          pos += 4;
+          prev_end = pos;
           continue;
         }
 
@@ -1649,13 +1006,13 @@ main(int argc, char *argv[])
 
           printf ("font\n");
 
-          pos += font_prefix_len - 1;
-          prev_end = pos + 1;
+          pos += font_prefix_len;
+          prev_end = pos;
           continue;
         }
 
       static const int string_prefix[] = {
-        0x80, 0x01, 0x02, 0x28, 0x05, 0x00, 0x01
+        0x05, 0x80, 0x01, 0x02, 0x28, 0x05, 0x00, 0x01
       };
       size_t string_prefix_len = sizeof string_prefix / sizeof *string_prefix;
       if (match_bytes(pos, string_prefix, string_prefix_len) && data[pos + string_prefix_len] != 255)
@@ -1668,10 +1025,10 @@ main(int argc, char *argv[])
             }
           prev_end = pos;
 
-          int len = data[pos + 7];
-          printf ("string %.*s\n", len, &data[pos + 8]);
-          pos += 8 + len - 1;
-          prev_end = pos + 1;
+          int len = data[pos + 8];
+          printf ("string %.*s\n", len, &data[pos + 9]);
+          pos += 8 + len;
+          prev_end = pos;
           continue;
         }
       if (match_bytes(pos, string_prefix, string_prefix_len) && data[pos + string_prefix_len] == 255)
@@ -1684,10 +1041,10 @@ main(int argc, char *argv[])
             }
           prev_end = pos;
 
-          int len = data[pos + 8] + (data[pos + 9] << 8);
-          printf ("\nlongstring %.*s\n", len, &data[pos + 10]);
-          pos += 10 + len - 1;
-          prev_end = pos + 1;
+          int len = data[pos + 9] + (data[pos + 10] << 8);
+          printf ("\nlongstring %.*s\n", len, &data[pos + 11]);
+          pos += 11 + len;
+          prev_end = pos;
           continue;
         }
 
@@ -1695,7 +1052,10 @@ main(int argc, char *argv[])
 
 
       if (!is_ascii(data[pos]))
-        continue;
+        {
+          pos++;
+          continue;
+        }
 
       unsigned int start = pos;
       unsigned int end = pos + 1;
@@ -1704,7 +1064,10 @@ main(int argc, char *argv[])
 
       unsigned int len = end - start;
       if (len < 3)
-        continue;
+        {
+          pos++;
+          continue;
+        }
 
       unsigned int len2 = data[start - 2] + (data[start - 1] << 8);
       unsigned int len3 = data[start - 1];
@@ -1720,9 +1083,15 @@ main(int argc, char *argv[])
           len = len3;
         }
       else
-        continue;
+        {
+          pos++;
+          continue;
+        }
       if (len < 3)
-        continue;
+        {
+          pos++;
+          continue;
+        }
       end = start + len;
 
       unsigned real_start = start - length_bytes;
@@ -1737,7 +1106,7 @@ main(int argc, char *argv[])
       printf ("\"%.*s\"\n", 
               (int) end - start, (char *) &data[start]);
       prev_end = end;
-      pos = end - 1;
+      pos = end;
     }
 
   exit(0);
index b7c1512e68e60575c9ad9bd7693f6b4d04ff61f4..92038d722c03b54136410024af846522cd94954b 100644 (file)
--- a/spo-notes
+++ b/spo-notes
@@ -247,40 +247,53 @@ ZMAW_zaj3.dump
 
 ----------------------------------------------------------------------
 
-rec:PMModelItemInfo
- .. .. .. .. .. .. .. .. .. .. .. .. ..                            cell F40.2 "Contents"
- 07 .. .. .. 55 80 .. 57 80 .. .. .. .. .. .. .. .. .. 07 .. 74 0e cell F40.2   "Output Created"
- .. .. .. .. 55 80 .. 57 80 .. 01 .. .. .. .. .. .. .. 08 .. 74 0e cell F40.2   "Comments"
- .. .. .. .. 55 80 .. 57 80 .. .. .. .. .. .. .. .. .. .. .. .. .. cell F40.2   "Input"
- 06 .. .. .. 55 80 .. 57 80 .. 02 .. .. .. .. .. .. .. 0a .. 74 0e cell F40.2     "Data"
- .. .. .. .. 55 80 .. 57 80 .. 03 .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Active Dataset"
- .. .. .. .. 55 80 .. 57 80 .. 04 .. .. .. .. .. .. .. 0e .. 74 0e cell F40.2     "Filter"
- .. .. .. .. 55 80 .. 57 80 .. 05 .. .. .. .. .. .. .. 11 .. 74 0e cell F40.2     "Weight"
- .. .. .. .. 55 80 .. 57 80 .. 06 .. .. .. .. .. .. .. 12 .. 74 0e cell F40.2     "Split File"
- .. .. .. .. 55 80 .. 57 80 .. 07 .. .. .. .. .. .. .. 13 .. 74 0e cell F40.2     "N of Rows in Working Data File"
- .. .. .. .. 55 80 .. 57 80 .. .. .. .. .. .. .. .. .. .. .. .. .. cell F40.2   "Missing Value Handling"
- 02 .. .. .. 55 80 .. 57 80 .. 08 .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Definition of Missing"
- .. .. .. .. 55 80 .. 57 80 .. 09 .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Cases Used"
- .. .. .. .. 55 80 .. 57 80 .. 0a .. .. .. .. .. .. .. 17 .. 74 0e cell F40.2   "Weight Handling"
- .. .. .. .. 55 80 .. 57 80 .. 0b .. .. .. .. .. .. .. 18 .. 74 0e cell F40.2   "Syntax"
- .. .. .. .. 55 80 .. 57 80 .. .. .. .. .. .. .. .. .. .. .. .. .. cell F40.2   "Resources"
- 03 .. .. .. 55 80 .. 57 80 .. 0c .. .. .. .. .. .. .. 1b .. 74 0e cell F40.2     "Elapsed Time"
- .. .. .. .. 55 80 .. 57 80 .. 0d .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Maximum Memory Required"
- .. .. .. .. 55 80 .. 57 80 .. 0e .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Processor Time"
-
-rec:PMModelItemInfo
-                            .. .. .. .. .. 01 .. .. .. ff ff ff ff cell F40.2       "score"
- 01 .. .. .. 86 80 .. 88 80 .. .. .. .. .. .. .. .. .. f4 0e 74 0e cell F40.2         "Valid"
- 09 .. .. .. 86 80 .. 88 80 .. .. .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "17..."
- .. .. .. .. 86 80 .. 88 80 .. 01 .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "22..."
- .. .. .. .. 86 80 .. 88 80 .. 02 .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "26..."
- .. .. .. .. 86 80 .. 88 80 .. 03 .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "29..."
- .. .. .. .. 86 80 .. 88 80 .. 04 .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "33..."
- .. .. .. .. 86 80 .. 88 80 .. 05 .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "37..."
- .. .. .. .. 86 80 .. 88 80 .. 06 .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "40..."
- .. .. .. .. 86 80 .. 88 80 .. 07 .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "48..."
- .. .. .. .. 86 80 .. 88 80 .. 08 .. .. .. .. .. .. .. f2 0e 74 0e cell F40.2         "Total"
- .. .. .. .. .. .. .. .. .. .. 09 .. .. .. 01 .. 90 .. 94 .. 98 .. 9c .. a0 .. a4 .. a8 .. ac .. b0 .. .. 09 .. .. .. .. .. .. .. .. .. 01 .. .. .. 02 .. .. .. 03 .. .. .. 04 .. .. .. 05 .. .. .. 06 .. .. .. 07 .. .. .. 08 .. ..
+rec:PMModelItemInfo 00
+ .. .. .. .. .. .. .. .. .. .. .. .. cell F40.2 "Contents"                           07 .. .. .. 55 80 .. 57 80 .. 
+ 00 .. .. .. .. .. .. .. 07 .. 74 0e cell F40.2   "Output Created"                   .. .. .. .. 55 80 .. 57 80 ..
+ 01 .. .. .. .. .. .. .. 08 .. 74 0e cell F40.2   "Comments"                         .. .. .. .. 55 80 .. 57 80 ..
+ .. .. .. .. .. .. .. .. .. .. .. .. cell F40.2   "Input"                            06 .. .. .. 55 80 .. 57 80 ..
+ 02 .. .. .. .. .. .. .. 0a .. 74 0e cell F40.2     "Data"                           .. .. .. .. 55 80 .. 57 80 ..
+ 03 .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Active Dataset"                 .. .. .. .. 55 80 .. 57 80 ..
+ 04 .. .. .. .. .. .. .. 0e .. 74 0e cell F40.2     "Filter"                         .. .. .. .. 55 80 .. 57 80 ..
+ 05 .. .. .. .. .. .. .. 11 .. 74 0e cell F40.2     "Weight"                         .. .. .. .. 55 80 .. 57 80 ..
+ 06 .. .. .. .. .. .. .. 12 .. 74 0e cell F40.2     "Split File"                     .. .. .. .. 55 80 .. 57 80 ..
+ 07 .. .. .. .. .. .. .. 13 .. 74 0e cell F40.2     "N of Rows in Working Data File" .. .. .. .. 55 80 .. 57 80 .. 
+ .. .. .. .. .. .. .. .. .. .. .. .. cell F40.2   "Missing Value Handling"           02 .. .. .. 55 80 .. 57 80 ..
+ 08 .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Definition of Missing"          .. .. .. .. 55 80 .. 57 80 ..
+ 09 .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Cases Used"                     .. .. .. .. 55 80 .. 57 80 ..
+ 0a .. .. .. .. .. .. .. 17 .. 74 0e cell F40.2   "Weight Handling"                  .. .. .. .. 55 80 .. 57 80 ..
+ 0b .. .. .. .. .. .. .. 18 .. 74 0e cell F40.2   "Syntax"                           .. .. .. .. 55 80 .. 57 80 ..
+ .. .. .. .. .. .. .. .. .. .. .. .. cell F40.2   "Resources"                        03 .. .. .. 55 80 .. 57 80 ..
+ 0c .. .. .. .. .. .. .. 1b .. 74 0e cell F40.2     "Elapsed Time"                   .. .. .. .. 55 80 .. 57 80 ..
+ 0d .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Maximum Memory Required"        .. .. .. .. 55 80 .. 57 80 ..
+ 0e .. .. .. .. .. .. .. .. .. .. .. cell F40.2     "Processor Time"
+
+ab1:
+
+rec:PMModelItemInfo ..
+ .. .. .. .. 01 .. .. .. 91 1a 74 0e cell F40.2 "Statistics"                         05 .. .. .. ff 7f 51 19 02 80 .. ff 7f 53 19 02 80 ..
+ 00 .. .. .. .. .. .. .. 98 1a 74 0e cell F40.2 "Pearson Correlation"                .. .. .. .. ff 7f 51 19 02 80 .. ff 7f 53 19 02 80 ..
+ 01 .. .. .. .. .. .. .. 99 1a 74 0e cell F40.2 "Sig. (2-tailed)"                    .. .. .. .. ff 7f 51 19 02 80 .. ff 7f 53 19 02 80 ..
+ 02 .. .. .. .. .. .. .. 96 1a 74 0e cell F40.2 "Sum of Squares and Cross-products"  .. .. .. .. ff 7f 51 19 02 80 .. ff 7f 53 19 02 80 ..
+ 03 .. .. .. .. .. .. .. 97 1a 74 0e cell F40.2 "Covariance"                         .. .. .. .. ff 7f 51 19 02 80 .. ff 7f 53 19 02 80 ..
+ 04 .. .. .. .. .. .. .. 94 1a 74 0e cell F40.2 "N"                                  .. .. .. .. .. .. .. .. .. ..
+ 05 .. .. .. 01 .. ff 7f 57 19 02 .. ff 7f 5b 19 02 .. ff 7f 5f 19 02 .. ff 7f 63 19 02 .. ff 7f 67 19 02 .. .. 05 .. .. .. .. .. .. .. .. .. 01 .. .. .. 02 .. .. .. 03 .. .. .. 04 .. .. .. ff 7f 4f 19 02 80 ..
+ ff 7f 51 19 02 80 .. ff 7f 53 19 02 80 ..
+ .. .. .. .. 01 .. .. .. 90 1a 74 0e
+
+rec:PMModelItemInfo .. ..
+ .. .. .. 01 .. .. .. ff ff ff ff cell F40.2       "score"      01 .. .. .. 86 80 .. 88 80 .. ..
+ .. .. .. .. .. .. .. f4 0e 74 0e cell F40.2         "Valid"    09 .. .. .. 86 80 .. 88 80 .. ..
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "17..."  .. .. .. .. 86 80 .. 88 80 .. 01
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "22..."  .. .. .. .. 86 80 .. 88 80 .. 02
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "26..."  .. .. .. .. 86 80 .. 88 80 .. 03
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "29..."  .. .. .. .. 86 80 .. 88 80 .. 04
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "33..."  .. .. .. .. 86 80 .. 88 80 .. 05
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "37..."  .. .. .. .. 86 80 .. 88 80 .. 06
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "40..."  .. .. .. .. 86 80 .. 88 80 .. 07
+ .. .. .. .. .. .. .. ff ff ff ff cell F40.2 xxx19     "48..."  .. .. .. .. 86 80 .. 88 80 .. 08
+ .. .. .. .. .. .. .. f2 0e 74 0e cell F40.2         "Total"    .. .. .. .. .. .. .. .. .. .. 09
+ .. .. .. 01 .. 90 .. 94 .. 98 .. 9c .. a0 .. a4 .. a8 .. ac .. b0 .. .. 09 .. .. .. .. .. .. .. .. .. 01 .. .. .. 02 .. .. .. 03 .. .. .. 04 .. .. .. 05 .. .. .. 06 .. .. .. 07 .. .. .. 08 .. ..
  .. 84 80 .. 86 80 .. 88 80 .. .. .. .. .. 01 .. .. .. eb 0e 74 0e cell F40.2       "Statistics"
  04 .. .. .. 86 80 .. 88 80 .. .. .. .. .. .. .. .. .. dc 0e 74 0e cell F40.2         "Frequency"
  .. .. .. .. 86 80 .. 88 80 .. 01 .. .. .. .. .. .. .. e6 0e 74 0e cell F40.2         "Percent"
@@ -288,14 +301,55 @@ rec:PMModelItemInfo
  .. .. .. .. 86 80 .. 88 80 .. 03 .. .. .. .. .. .. .. da 0e 74 0e cell F40.2         "Cumulative Percent"
  .. .. .. .. .. .. .. .. .. .. 04 .. .. .. 01 .. b9 .. bd .. c1 .. c5 .. .. 04 .. .. .. .. .. .. .. .. .. 01 .. .. .. 02 .. .. .. 03 .. .. .. .. .. .. .. .. 01 .. .. 11 .. .. .. .. .. .. .. .. .. 4b .. .. .. .. .. .. .. .. .. .. ..
 
-rec:PMModelItemInfo
-                            .. .. .. .. .. 01 .. .. .. 91 1a 74 0e cell F40.2 "Statistics"
- 05 .. .. .. ff 7f 69 78 02 80 .. ff 7f 6b 78 02 80 .. .. .. .. .. .. .. .. .. 98 1a 74 0e cell F40.2   "Pearson Correlation"
- .. .. .. .. ff 7f 69 78 02 80 .. ff 7f 6b 78 02 80 .. 01 .. .. .. .. .. .. .. 99 1a 74 0e cell F40.2   "Sig. (2-tailed)"
- .. .. .. .. ff 7f 69 78 02 80 .. ff 7f 6b 78 02 80 .. 02 .. .. .. .. .. .. .. 96 1a 74 0e cell F40.2   "Sum of Squares and Cross-products"
- .. .. .. .. ff 7f 69 78 02 80 .. ff 7f 6b 78 02 80 .. 03 .. .. .. .. .. .. .. 97 1a 74 0e cell F40.2   "Covariance"
- .. .. .. .. ff 7f 69 78 02 80 .. ff 7f 6b 78 02 80 .. 04 .. .. .. .. .. .. .. 94 1a 74 0e cell F40.2   "N"
- .. .. .. .. .. .. .. .. .. .. 05 .. .. .. 01 .. ff 7f 6f 78 02 .. ff 7f 73 78 02 .. ff 7f 77 78 02 .. ff 7f 7b 78 02 .. ff 7f 7f 78 02 .. .. 05 .. .. .. .. .. .. .. .. .. 01 .. .. .. 02 .. .. .. 03 .. .. .. 04 .. .. .. ff 7f 67 78 02 80 .. ff 7f 69 78 02 80 .. ff 7f 6b 78 02 80 .. .. .. .. .. 01 .. .. .. 90 1a 74 0e ..................ox....sx....wx....{x.....x...............................gx.....ix.....kx.............t.
+Output_201B:
+
+rec:PMModelItemInfo       00
+00 00 00 00 01 00 00 00 00 00 00 00 cell F40.2 "Variables" 5a 00 00 00 64 85 00 66 85 00
+00 00 00 00 00 00 00 00 ff ff ff ff cell F40.2 "i10149"    00 00 00 00 64 85 00 66 85 00
+01 00 00 00 00 00 00 00 ff ff ff ff cell F40.2 "i10150"    00 00 00 00 64 85 00 66 85 00
+02 00 00 00 00 00 00 00 ff ff ff ff cell F40.2 "i10154"    00 00 00 00 64 85 00 66 85 00
+03 00 00 00 00 00 00 00 ff ff ff ff cell F40.2 "i10168"    00 00 00 00 64 85 00 66 85 00
+04 00 00 00 00 00 00 00 ff ff ff ff cell F40.2 "i10171"    00 00 00 00 64 85 00 66 85 00
+05 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10183"
+ 00 00 00 00 64 85 00 66 85 00 06 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10184"
+ 00 00 00 00 64 85 00 66 85 00 07 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10212"
+ 00 00 00 00 64 85 00 66 85 00 08 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10220"
+ 00 00 00 00 64 85 00 66 85 00 09 00 00 00 00 00 00 00 ff ff ff ff ....d..f..............
+cell F40.2 "i10222"
+ 00 00 00 00 64 85 00 66 85 00 0a 00 00 00 00 00 00 00 ff ff ff ff ....d..f..............
+cell F40.2 "i10226"
+ 00 00 00 00 64 85 00 66 85 00 0b 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10228"
+ 00 00 00 00 64 85 00 66 85 00 0c 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10229"
+ 00 00 00 00 64 85 00 66 85 00 0d 00 00 00 00 00 00 00 ff ff ff ff ....d..f..............
+cell F40.2 "i10230"
+ 00 00 00 00 64 85 00 66 85 00 0e 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10234"
+ 00 00 00 00 64 85 00 66 85 00 0f 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10244"
+ 00 00 00 00 64 85 00 66 85 00 10 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10247"
+ 00 00 00 00 64 85 00 66 85 00 11 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10250"
+ 00 00 00 00 64 85 00 66 85 00 12 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10265"
+ 00 00 00 00 64 85 00 66 85 00 13 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10266"
+ 00 00 00 00 64 85 00 66 85 00 14 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10269"
+ 00 00 00 00 64 85 00 66 85 00 15 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10270"
+ 00 00 00 00 64 85 00 66 85 00 16 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10272"
+ 00 00 00 00 64 85 00 66 85 00 17 00 00 00 00 00 00 00 ff ff ff ff
+cell F40.2 "i10286"
+ 00 00 00 00 64 85 00 66 85 00 18 00 00 00 00 00 00 00 ff ff ff ff
+
 
 
 ff is a way to say that there's a 4-byte number instead of 1-byte?