spo: learned things
[pspp] / dump-spo.c
index b48110736e008d6dd2907ba975e4d7ecafb16018..ac53ece628894626236a24d2c2d9a91537d33b12 100644 (file)
@@ -265,16 +265,21 @@ get_end(void)
 static void __attribute__((unused))
 hex_dump(FILE *stream, int ofs, int n)
 {
+  int n_ascii = 0;
   for (int i = 0; i < n; i++)
     {
       int c = data[ofs + i];
+      n_ascii += is_ascii(c);
       fprintf(stream, " %02x", c);
     }
-  putc(' ', stream);
-  for (int i = 0; i < n; i++)
+  if (n_ascii >= 3)
     {
-      int c = data[ofs + i];
-      putc(c >= 32 && c < 127 ? c : '.', stream);
+      putc(' ', stream);
+      for (int i = 0; i < n; i++)
+        {
+          int c = data[ofs + i];
+          putc(c >= 32 && c < 127 ? c : '.', stream);
+        }
     }
   putc('\n', stream);
 }
@@ -1258,6 +1263,52 @@ dump_fonts(void)
     }
 }
 
+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;
+    }
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -1336,31 +1387,77 @@ main(int argc, char *argv[])
   for (pos = 2; pos + 50 < n; pos++)
     {
       static const int cell_prefix[] = {
-        0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, -1, 0x80, 0x01, -1, -1,
-        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        0x00, 0x03,
+        0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -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))
         {
           if (prev_end != pos)
             {
-              printf ("%04x ", prev_end);
+              //printf ("%04x ", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
-          double d = *(double *) &data[pos + cell_prefix_len - 8];
-          const union
+          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)
+            {
+              assert (data[pos + 13] == 5);
+              if (data[pos + 20] == 0)
+                {
+                  int count = (data[pos + 22]);
+                  printf ("%d %d \"%.*s\"\n",
+                          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\"\n", count, data[pos + 23],
+                          &data[pos + 24]);
+                  len = 23 + count;
+                }
+              else if (data[pos + 20] == 1)
+                {
+                  int count = (data[pos + 21]);
+                  printf ("\"%.*s\"\n",
+                          count, &data[pos + 22]);
+                  len = 22 + count;
+                }
+              else
+                abort ();
+            }
+          else if (data[pos + 19] == 128)
             {
-              uint8_t b[8];
-              double d;
+              /* pos + 13 is usually 22...53 but also 5 or 69 */
+              /* pos + 20 is 2 most of the time, occasionally 1 */
+              printf ("%d %d ", data[pos + 13], data[pos + 20]);
+              double d = *(double *) &data[pos + 21];
+              len = 29;
+              const union
+                {
+                  uint8_t b[8];
+                  double d;
+                }
+              sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
+              if (d == sysmis.d)
+                printf ("sysmis\n");
+              else
+                printf ("%f\n", d);
             }
-          sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
-          if (d == sysmis.d)
-            printf ("cell sysmis\n");
           else
-            printf ("cell %f\n", d);
-          pos += cell_prefix_len - 1;
+            abort ();
+          pos += len - 1;
           prev_end = pos + 1;
           continue;
         }
@@ -1373,7 +1470,7 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              printf ("%04x ", prev_end);
+              //printf ("%04x ", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1383,6 +1480,87 @@ main(int argc, char *argv[])
           continue;
         }
 
+      static const int record_prefix[] = {
+        0xff, 0xff, 0x00, 0x00,
+      };
+      size_t record_prefix_len = sizeof record_prefix / sizeof *record_prefix;
+      if (match_bytes(pos, record_prefix, record_prefix_len))
+        {
+          if (prev_end != pos)
+            {
+              //printf ("%04x ", prev_end);
+              hex_dump (stdout, prev_end, pos - prev_end);
+            }
+
+          putchar ('\n');
+
+          //printf ("%d ", pos % 4);
+          int len = record_prefix_len;
+          int slen = data[pos + 4] + (data[pos + 5] << 8);
+          if (slen > 2 && slen < 256 && all_utf8((char *) &data[pos + 6], slen))
+            {
+              printf ("%.*s ", slen, &data[pos + 6]);
+              len = slen + 6;
+            }
+          else
+            printf ("notitle ");
+
+          pos += len - 1;
+          prev_end = pos + 1;
+          continue;
+        }
+
+      static const int number_prefix[] = {
+        0x80, 0x02
+      };
+      size_t number_prefix_len = sizeof number_prefix / sizeof *number_prefix;
+      if (match_bytes(pos, number_prefix, number_prefix_len))
+        {
+          if (prev_end != pos)
+            {
+              //printf ("%04x ", prev_end);
+              hex_dump (stdout, prev_end, pos - prev_end);
+            }
+          prev_end = pos;
+
+          double d = *(double *) &data[pos + number_prefix_len];
+          printf ("float%f ", d);
+          pos += 10 - 9;
+          prev_end = pos + 1;
+          continue;
+        }
+
+      static const int string_prefix[] = {
+        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)
+        {
+          if (prev_end != pos)
+            {
+              //printf ("%04x ", prev_end);
+              hex_dump (stdout, prev_end, pos - prev_end);
+            }
+          prev_end = pos;
+
+          printf ("\nstring %.*s\n", (int) data[pos + 7], &data[pos + 8]);
+        }
+      if (match_bytes(pos, string_prefix, string_prefix_len) && data[pos + string_prefix_len] == 255)
+        {
+          if (prev_end != pos)
+            {
+              //printf ("%04x ", prev_end);
+              hex_dump (stdout, prev_end, pos - prev_end);
+            }
+          prev_end = pos;
+
+          int len = data[pos + 8] + (data[pos + 9] << 8);
+          printf ("\nlongstring %.*s\n", len, &data[pos + 10]);
+        }
+
+      
+
+#if 0
       static const int heading_prefix[] = {
         -1, 0x00, 0x00, 0x00, 0x50, 0x80, 0x00, 0x52, 0x80, 0x00, -1, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
@@ -1394,7 +1572,7 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              printf ("%04x ", prev_end);
+              //printf ("%04x ", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1405,20 +1583,20 @@ main(int argc, char *argv[])
         }
 
       static const int font_prefix[] = {
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x80, 0x00, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xa9,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, 0x80, 0x00, 0x01, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, -1,
         0x80, 0x00, -1, 0x00, -1, 0x00, 0xc8, 0x00, -1, -1, -1, -1, -1,
-        0x00, -1, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf3,
+        0x00, -1, 0x00, 0x00, 0x00, 0x01, 0x00, -1,
         0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x22,
+        0x00, 0x00, -1 /* 12 or 22 */,
       };
       size_t font_prefix_len = sizeof font_prefix / sizeof *font_prefix;
       if (match_bytes(pos, font_prefix, font_prefix_len))
         {
           if (prev_end != pos)
             {
-              printf ("%04x", prev_end);
+              //printf ("%04x", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1433,41 +1611,41 @@ main(int argc, char *argv[])
         }
 
       static const int table_prefix[] = {
-        0x00, 0x00, 0xed, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+        -1 /* ed or e9 */, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x41, 0x72, 0x69,
-        0x61, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x61, 0x6c, 0x00, -1, 0x00, -1, 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, 0x01, 0x00, 0x00, 0x00, -1, 0x01, 0x00,
-        0x00,
+        0x00, 0x00, 0x00, 0x00, -1, 0x00, 0x00, 0x00, -1,
       };
       size_t table_prefix_len = sizeof table_prefix / sizeof *table_prefix;
       if (match_bytes(pos, table_prefix, table_prefix_len))
         {
           if (prev_end != pos)
             {
-              printf ("%04x", prev_end);
+              //printf ("%04x", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
-          printf ("table %d\n", data[pos + 74]);
+          printf ("table %d\n", data[pos + 72]);
           pos += table_prefix_len - 1;
           prev_end = pos + 1;
           continue;
         }
+#endif
 
       static const int dim_prefix[] = {
         0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, -1,
         0x00, 0x00, 0x00, 0x00, -1, 0x80, 0x01, 0x02, -1,
-        -1, -1, 0x01,
+        -1, -1, -1 /* 00 or 01 */,
       };
       size_t dim_prefix_len = sizeof dim_prefix / sizeof *dim_prefix;
       if (match_bytes(pos, dim_prefix, dim_prefix_len))
         {
           if (prev_end != pos)
             {
-              printf ("%04x", prev_end);
+              //printf ("%04x", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1487,7 +1665,7 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              printf ("%04x", prev_end);
+              //printf ("%04x", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1533,10 +1711,11 @@ main(int argc, char *argv[])
       unsigned real_start = start - length_bytes;
       if (prev_end != real_start)
         {
-          printf ("%04x ", prev_end);
+          //printf ("%04x ", prev_end);
           hex_dump (stdout, prev_end, real_start - prev_end);
         }
-      printf ("%04x \"%.*s\"\n", real_start,
+      //printf ("%04x ", real_start);
+      printf ("\"%.*s\"\n", 
               (int) end - start, (char *) &data[start]);
       prev_end = end;
       pos = end - 1;