work on spo files
[pspp] / dump-spo2.c
diff --git a/dump-spo2.c b/dump-spo2.c
new file mode 100644 (file)
index 0000000..3367163
--- /dev/null
@@ -0,0 +1,467 @@
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <float.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include "u8-mbtouc.h"
+
+static const char *filename;
+static uint8_t *data;
+static size_t n;
+
+int version;
+
+unsigned int pos;
+
+#define XSTR(x) #x
+#define STR(x) XSTR(x)
+#define WHERE __FILE__":" STR(__LINE__)
+
+static uint8_t
+get_byte(void)
+{
+  return data[pos++];
+}
+
+static unsigned int
+get_u32(void)
+{
+  uint32_t x;
+  memcpy(&x, &data[pos], 4);
+  pos += 4;
+  return x;
+}
+
+static unsigned long long int
+get_u64(void)
+{
+  uint64_t x;
+  memcpy(&x, &data[pos], 8);
+  pos += 8;
+  return x;
+}
+
+static unsigned int
+get_be32(void)
+{
+  uint32_t x;
+  x = (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3];
+  pos += 4;
+  return x;
+}
+
+static unsigned int
+get_u16(void)
+{
+  uint16_t x;
+  memcpy(&x, &data[pos], 2);
+  pos += 2;
+  return x;
+}
+
+static double
+get_double(void)
+{
+  double x;
+  memcpy(&x, &data[pos], 8);
+  pos += 8;
+  return x;
+}
+
+static double __attribute__((unused))
+get_float(void)
+{
+  float x;
+  memcpy(&x, &data[pos], 4);
+  pos += 4;
+  return x;
+}
+
+static bool
+match_u32(uint32_t x)
+{
+  if (get_u32() == x)
+    return true;
+  pos -= 4;
+  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)
+{
+  unsigned int y = get_u32();
+  if (x != y)
+    {
+      fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
+      exit(1);
+    }
+}
+#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)
+{
+  if (get_u64() == x)
+    return true;
+  pos -= 8;
+  return false;
+}
+
+static void __attribute__((unused))
+match_u64_assert(uint64_t x, const char *where)
+{
+  unsigned long long int y = get_u64();
+  if (x != y)
+    {
+      fprintf(stderr, "%s: 0x%x: expected u64:%lu, got u64:%llu\n", where, pos - 8, x, y);
+      exit(1);
+    }
+}
+#define match_u64_assert(x) match_u64_assert(x, WHERE)
+
+static bool __attribute__((unused))
+match_be32(uint32_t x)
+{
+  if (get_be32() == x)
+    return true;
+  pos -= 4;
+  return false;
+}
+
+static void
+match_be32_assert(uint32_t x, const char *where)
+{
+  unsigned int y = get_be32();
+  if (x != y)
+    {
+      fprintf(stderr, "%s: 0x%x: expected be%u, got be%u\n", where, pos - 4, x, y);
+      exit(1);
+    }
+}
+#define match_be32_assert(x) match_be32_assert(x, WHERE)
+
+static bool
+match_byte(uint8_t b)
+{
+  if (pos < n && data[pos] == b)
+    {
+      pos++;
+      return true;
+    }
+  else
+    return false;
+}
+
+static void
+match_byte_assert(uint8_t b, const char *where)
+{
+  if (!match_byte(b))
+    {
+      fprintf(stderr, "%s: 0x%x: expected %02x, got %02x\n", where, pos, b, data[pos]);
+      exit(1);
+    }
+}
+#define match_byte_assert(b) match_byte_assert(b, WHERE)
+
+static bool
+match_bytes(int start, const int *bytes, size_t n_bytes)
+{
+  for (size_t i = 0; i < n_bytes; i++)
+    if (bytes[i] >= 0 && data[start + i] != bytes[i])
+      return false;
+  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)
+{
+  if (match_byte(0))
+    return false;
+  match_byte_assert(1);
+  return true;
+}
+
+static bool __attribute__((unused))
+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)
+{
+  const uint8_t *p = (const uint8_t *) p_;
+  for (size_t ofs = 0, mblen; ofs < len; ofs += mblen)
+    {
+      ucs4_t uc;
+
+      mblen = u8_mbtouc (&uc, p + ofs, len - ofs);
+      if ((uc < 32 && uc != '\n') || uc == 127 || uc == 0xfffd)
+        return false;
+    }
+  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)
+{
+  if (1
+      /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
+      /*&& all_ascii(&data[pos + 4], data[pos])*/)
+    {
+      int len = data[pos] + data[pos + 1] * 256;
+      char *s = malloc(len + 1);
+
+      memcpy(s, &data[pos + 4], len);
+      s[len] = 0;
+      pos += 4 + len;
+      return s;
+    }
+  else
+    {
+      fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
+      exit(1);
+    }
+}
+#define get_string() get_string(WHERE)
+
+static char *
+get_string_be(const char *where)
+{
+  if (1
+      /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
+      /*&& all_ascii(&data[pos + 4], data[pos])*/)
+    {
+      int len = data[pos + 2] * 256 + data[pos + 3];
+      char *s = malloc(len + 1);
+
+      memcpy(s, &data[pos + 4], len);
+      s[len] = 0;
+      pos += 4 + len;
+      return s;
+    }
+  else
+    {
+      fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
+      exit(1);
+    }
+}
+#define get_string_be() get_string_be(WHERE)
+
+static int
+get_end(void)
+{
+  int len = get_u32();
+  return pos + len;
+}
+
+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);
+    }
+  if (n_ascii >= 3)
+    {
+      putc(' ', stream);
+      for (int i = 0; i < n; i++)
+        {
+          int c = data[ofs + i];
+          putc(c >= 32 && c < 127 ? c : '.', stream);
+        }
+    }
+  putc('\n', stream);
+}
+
+static void __attribute__((unused))
+char_dump(FILE *stream, int ofs, int n)
+{
+  for (int i = 0; i < n; i++)
+    {
+      int c = data[ofs + i];
+      putc(c >= 32 && c < 127 ? c : '.', stream);
+    }
+  putc('\n', stream);
+}
+
+
+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 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: case 40: 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";
+    default: sprintf(buf, "(%d)", format); return buf;
+    }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+  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);
+    }
+
+  const char *filename = argv[optind];
+  int fd = open(filename, O_RDONLY);
+  if (fd < 0)
+    {
+      fprintf (stderr, "%s: open failed (%s)", filename, strerror (errno));
+      exit (1);
+    }
+
+  struct stat s;
+  if (fstat(fd, &s))
+    {
+      perror("fstat");
+      exit(1);
+    }
+  n = s.st_size;
+  data = malloc(n);
+  if (!data)
+    {
+      perror("malloc");
+      exit(1);
+    }
+  if (read(fd, data, n) != n)
+    {
+      perror("read");
+      exit(1);
+    }
+  close(fd);
+
+  setvbuf (stdout, NULL, _IOLBF, 0);
+
+  return 0;
+}