significant progess on SPOs
[pspp] / dump-spo.c
index ac53ece628894626236a24d2c2d9a91537d33b12..35cd8b5dcc072e837b32ce051198419e99870bd5 100644 (file)
@@ -179,6 +179,15 @@ match_bytes(int start, const int *bytes, size_t n_bytes)
   return true;
 }
 
+static char *
+xmemdup0(const void *p, size_t n)
+{
+  char *s = malloc(n + 1);
+  memcpy(s, p, n);
+  s[n] = 0;
+  return s;
+}
+
 static bool
 get_bool(void)
 {
@@ -516,7 +525,7 @@ format_to_string (int type)
     case 38: return "EDATE";
     case 39: return "SDATE";
     default:
-      abort();
+      assert(false);
       sprintf(tmp, "<%d>", type);
       return tmp;
     }
@@ -1312,13 +1321,30 @@ format_name (int format, char *buf)
 int
 main(int argc, char *argv[])
 {
-  if (argc != 2)
+  bool print_offsets = false;
+  for (;;)
+    {
+      int c = getopt (argc, argv, "o");
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case 'o':
+          print_offsets = true;
+          break;
+
+        case '?':
+          exit (-1);
+        }
+    }
+  if (argc - optind != 1)
     {
       fprintf (stderr, "usage: %s FILE.bin", argv[0]);
       exit (1);
     }
 
-  filename = argv[1];
+  const char *filename = argv[optind];
   int fd = open(filename, O_RDONLY);
   if (fd < 0)
     {
@@ -1346,6 +1372,10 @@ main(int argc, char *argv[])
     }
   close(fd);
 
+  setvbuf (stdout, NULL, _IOLBF, 0);
+
+  int sum = 0;
+  
 #if 0
   unsigned int prev_end = 0;
   for (pos = 0; pos + 50 < n; pos++)
@@ -1375,7 +1405,8 @@ main(int argc, char *argv[])
           !all_utf8((char *) &data[pos + 3], 1) &&
           data[pos - 1] != 'v')
         {
-          //printf ("%04x: ", pos);
+          if (print_offsets)
+            printf ("%04x: ", pos);
           unsigned int p = pos;
           while (all_utf8 ((char *) &data[p], 1))
             p--;
@@ -1384,11 +1415,14 @@ main(int argc, char *argv[])
     }
 #endif
   unsigned int prev_end = 0;
+  char *title = "";
   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, 0x00, 0x00, 0x00, 0x00, 0x00, -1 /* 00 or 10 */, 0x00, 0x00, 0x00, 0x00, -1,
+
+        /*14    15  16  17  18  19 */
         0x80, 0x01, -1, -1, -1, -1,
       };
       size_t cell_prefix_len = sizeof cell_prefix / sizeof *cell_prefix;
@@ -1396,8 +1430,19 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              //printf ("%04x ", prev_end);
+              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];
@@ -1435,13 +1480,13 @@ main(int argc, char *argv[])
                   len = 22 + count;
                 }
               else
-                abort ();
+                assert (false);
             }
-          else if (data[pos + 19] == 128)
+          else if (data[pos + 19] == 128 && data[pos + 20] == 2)
             {
-              /* 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]);
+              /* 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
@@ -1451,17 +1496,48 @@ main(int argc, char *argv[])
                 }
               sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
               if (d == sysmis.d)
-                printf ("sysmis\n");
+                printf ("sysmis");
+              else
+                printf ("%f", d);
+
+              if (data[pos + 29] < 0xff
+                  && all_utf8((char *) &data[pos + 30], data[pos + 29]))
+                {
+                  printf (" \"%.*s\"", (int) data[pos + 29],
+                          &data[pos + 30]);
+                  len += data[pos + 29] + 1;
+                }
               else
-                printf ("%f\n", d);
+                assert (false);
+
+              putchar ('\n');
+            }
+          else if (data[pos + 19] == 128 && data[pos + 20] == 1 &&
+                   data[pos + 21] == 0)
+            {
+              if (data[pos + 23] < 0xff
+                  && all_utf8((char *) &data[pos + 24], data[pos + 23]))
+                {
+                  printf (" \"%.*s\"\n", (int) data[pos + 23],
+                          &data[pos + 24]);
+                  len = 24 + data[pos + 23];
+                }
+              else
+                assert (false);
             }
           else
-            abort ();
+            {
+              printf ("xxx%d %d %d %d\n",
+                      data[pos + 19], data[pos + 20],
+                      data[pos + 21], data[pos + 22]);
+              assert(false);
+            }
           pos += len - 1;
           prev_end = pos + 1;
           continue;
         }
 
+#if 0
       static const int col_prefix[] = {
         0x11, 0x80, 0x00, -1, 0x00, 0x00, 0x00, 0x01, 0x00
       };
@@ -1470,7 +1546,8 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              //printf ("%04x ", prev_end);
+              if (print_offsets)
+                printf ("%04x ", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1479,35 +1556,37 @@ main(int argc, char *argv[])
           prev_end = pos + 1;
           continue;
         }
-
+#endif
+      
       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))
+          if (slen >= 2 && slen < 256 && all_utf8((char *) &data[pos + 6], slen))
             {
-              printf ("%.*s ", slen, &data[pos + 6]);
+              if (prev_end != pos)
+                {
+                  if (print_offsets)
+                    printf ("%04x ", prev_end);
+                  hex_dump (stdout, prev_end, pos - prev_end);
+                }
+
+              putchar ('\n');
+
+              printf ("rec:%-20.*s ", slen, &data[pos + 6]);
               len = slen + 6;
-            }
-          else
-            printf ("notitle ");
+              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;
-          continue;
+              pos += len - 1;
+              prev_end = pos + 1;
+              continue;
+            }
         }
 
       static const int number_prefix[] = {
@@ -1518,18 +1597,41 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              //printf ("%04x ", prev_end);
+              if (print_offsets)
+                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;
+          printf ("float %f\n", d);
+
+          pos += 10 - 1;
           prev_end = pos + 1;
           continue;
         }
 
+      if (!memcmp (&data[pos + 4], "{\\rtf", 5))
+        {
+          int len = data[pos] + (data[pos + 1] << 8) + (data[pos + 2] << 16)
+            + (data[pos + 3] << 24);
+          if (len < n - pos - 4)
+            {
+              if (prev_end != pos)
+                {
+                  if (print_offsets)
+                    printf ("%04x ", prev_end);
+                  hex_dump (stdout, prev_end, pos - prev_end);
+                }
+              prev_end = pos;
+
+              printf ("rtf\n");
+              pos += 4 + len - 1;
+              prev_end = pos + 1;
+              continue;
+            }
+        }
+
       static const int string_prefix[] = {
         0x80, 0x01, 0x02, 0x28, 0x05, 0x00, 0x01
       };
@@ -1538,24 +1640,33 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              //printf ("%04x ", prev_end);
+              if (print_offsets)
+                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]);
+          int len = data[pos + 7];
+          printf ("string %.*s\n", len, &data[pos + 8]);
+          pos += 8 + len - 1;
+          prev_end = pos + 1;
+          continue;
         }
       if (match_bytes(pos, string_prefix, string_prefix_len) && data[pos + string_prefix_len] == 255)
         {
           if (prev_end != pos)
             {
-              //printf ("%04x ", prev_end);
+              if (print_offsets)
+                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]);
+          pos += 10 + len - 1;
+          prev_end = pos + 1;
+          continue;
         }
 
       
@@ -1572,7 +1683,8 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              //printf ("%04x ", prev_end);
+              if (print_offsets)
+                printf ("%04x ", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1582,6 +1694,7 @@ main(int argc, char *argv[])
           continue;
         }
 
+#if 0
       static const int font_prefix[] = {
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, 0x80, 0x00, 0x01, 0x00,
         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, -1,
@@ -1596,7 +1709,8 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              //printf ("%04x", prev_end);
+              if (print_offsets)
+            printf ("%04x", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1609,7 +1723,8 @@ main(int argc, char *argv[])
           prev_end = pos + 1;
           continue;
         }
-
+#endif
+      
       static const int table_prefix[] = {
         -1 /* ed or e9 */, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x00,
@@ -1624,7 +1739,8 @@ main(int argc, char *argv[])
         {
           if (prev_end != pos)
             {
-              //printf ("%04x", prev_end);
+              if (print_offsets)
+                printf ("%04x", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
@@ -1633,49 +1749,28 @@ main(int argc, char *argv[])
           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, -1 /* 00 or 01 */,
+        0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x01, 0x02, 0x28,
+        0x05, 0x00,
       };
       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);
+              if (print_offsets)
+                printf ("%04x", prev_end);
               hex_dump (stdout, prev_end, pos - prev_end);
             }
 
-          printf ("dim %d %d %d %d %d\n", data[pos + 8], data[pos + 13],
-                  data[pos + 17], data[pos + 18], data[pos + 19]);
+          printf ("dim %d\n", data[pos + 8]);
           pos += dim_prefix_len - 1;
           prev_end = pos + 1;
           continue;
         }
-
-      static const int dim2_prefix[] = {
-        0x50, 0x80, 0x00, 0x52, 0x80, 0x00, -1, 0x00, 0x00, 0x00, -1, 0, 0, 0,
-        -1, -1, -1, -1
-      };
-      size_t dim2_prefix_len = sizeof dim2_prefix / sizeof *dim2_prefix;
-      if (match_bytes(pos, dim2_prefix, dim2_prefix_len))
-        {
-          if (prev_end != pos)
-            {
-              //printf ("%04x", prev_end);
-              hex_dump (stdout, prev_end, pos - prev_end);
-            }
-
-          int16_t x = *(int16_t *) &data[pos + 14];
-          int16_t y = *(int16_t *) &data[pos + 16];
-          printf ("dim2 %d %d %d %d\n", data[pos + 6], data[pos + 10], x, y);
-          pos += dim2_prefix_len - 1;
-          prev_end = pos + 1;
-          continue;
-        }
+#endif
 
       if (!is_ascii(data[pos]))
         continue;
@@ -1711,10 +1806,12 @@ main(int argc, char *argv[])
       unsigned real_start = start - length_bytes;
       if (prev_end != real_start)
         {
-          //printf ("%04x ", prev_end);
+          if (print_offsets)
+            printf ("%04x ", prev_end);
           hex_dump (stdout, prev_end, real_start - prev_end);
         }
-      //printf ("%04x ", real_start);
+      if (print_offsets)
+        printf ("%04x ", real_start);
       printf ("\"%.*s\"\n", 
               (int) end - start, (char *) &data[start]);
       prev_end = end;