}
static void
-dump_category (int level, uint8_t *catstart, bool *have_catstart)
+dump_category (int level, uint8_t *delim, int *delim_len)
{
int cat_index = get_u32();
assert (cat_index < 256);
printf (" (group with %d children)", n_children);
else
printf (" (category #%d)", cat_index);
+ printf ("\n");
- 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)
+ int dlen = 0;
+ for (int i = 0; i < 2; i++)
{
- *have_catstart = true;
- memcpy(catstart, &data[pos], 6);
+ if (data[pos + dlen] == 0xff)
+ dlen += 7;
+ else
+ dlen += 3;
+ }
+ if (!*delim_len)
+ {
+ *delim_len = dlen;
+ memcpy(delim, &data[pos], dlen);
}
- pos += 6;
+ pos += dlen;
for (int i = 0; i < n_children; i++)
- dump_category (level + 1, catstart, have_catstart);
+ dump_category (level + 1, delim, delim_len);
}
static void
dump_PMModelItemInfo(int ndims)
{
- return;
#if 0
if (data[pos + 9] && data[pos + 9] != 0xff)//count_zeros (&data[pos + 9]) < 4)
return;
match_byte_assert (0);
- uint8_t catstart[6];
- bool have_catstart = false;
- dump_category (0, catstart, &have_catstart);
- assert(have_catstart);
+ uint8_t delim[14];
+ int delim_len = 0;
+ dump_category (0, delim, &delim_len);
+ assert(delim_len);
for (int i = 1; i < ndims; i++)
{
for (int j = 0; ; j++, pos++)
{
- assert (j <= 1000);
- if (!memcmp(&data[pos], catstart, 6))
+ assert (pos + j + delim_len < n);
+ if (!memcmp(&data[pos], delim, delim_len))
break;
}
- pos += 6;
+ pos += delim_len;
- dump_category (0, catstart, &have_catstart);
+ dump_category (0, delim, &delim_len);
}
}
setvbuf (stdout, NULL, _IOLBF, 0);
+ pos = 0x39b;
+ unsigned int rtflen = get_u32();
+ pos += rtflen - 1; /* Almost past SPSS syntax */
+ assert(pos < n);
+ pos += 0x45 + data[pos + 0x44]; /* Just past the string */
+ pos += 0x1a + data[pos + 0x19]; /* Just past the string again */
+ pos += 0x66 + data[pos + 0x65]; /* Just past the third string */
+ pos += 0x4e;
+ rtflen = get_u32();
+ pos += rtflen - 1; /* Almost past 2nd RTF */
+ pos += 0x64 + data[pos + 0x63]; /* Just past the fourth string */
+ /* as-number: */
+ if (data[pos + 0x114] == 0xff)
+ pos += 0x117 + data[pos + 0x115] + 256 * data[pos + 0x116];
+ else
+ pos += 0x115 + data[pos + 0x114];
+ pos += 0x18 + data[pos + 0x17]; /* Just past "<none>" or dataset name. */
+ pos += 0x18 + data[pos + 0x17]; /* Just past "<none>" or dataset name. */
+ pos += count_zeros(&data[pos]); /* Skip optional zeros. */
+ pos += 0x18 + data[pos + 0x17]; /* Just past "<none>" or dataset name. */
+ pos += 0x3e + data[pos + 0x3d]; /* Skip past "100" etc. */
+ pos += count_zeros(&data[pos]); /* Skip optional zeros. */
+ pos += 0x18 + data[pos + 0x17]; /* Just past "User-defined...". */
+ pos += 0x18 + data[pos + 0x17]; /* Just past "Statistics are based... */
+ if (data[pos + 0x19] == 0xff)
+ pos += 0x1c + data[pos + 0x1a] + 256 * data[pos + 0x1b];
+ else
+ pos += 0x1a + data[pos + 0x19];
+ pos += 0x61 + data[pos + 0x60]; /* Just past "Cluster_Notes". */
+ pos += 0x992 + data[pos + 0x991]; /* Just past "Cluster". */
+ pos += 0x4e;
+ rtflen = get_u32();
+ pos += rtflen - 1; /* Almost past RTF with filesystem path */
+ pos += 0x45 + data[pos + 0x44]; /* Just past "Statistics" */
+ pos += 0x1a + data[pos + 0x19]; /* Just past "Cluster". */
+ fwrite (&data[pos], 1, n - pos, stdout);
+ exit (0);
+
int sum = 0;
#if 0
continue;
}
-
+ if (data[pos] == 0 && data[pos + 1] == 0xff
+ && (!data[pos + 2] || data[pos + 2] == 0xff) && data[pos + 3] == 0xff
+ && data[pos + 4] == 0)
+ {
+ pos++;
+ if (prev_end != pos)
+ {
+ if (print_offsets)
+ printf ("%04x ", prev_end);
+ hex_dump (stdout, prev_end, pos - prev_end);
+ }
+ prev_end = pos;
+ continue;
+ }
if (!is_ascii(data[pos]))
--- /dev/null
+#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;
+}
01 02 28 (00|05) 00 (00|01)
often followed by a string
+The first byte might be a version number. "Save As" or "Save" has the effect:
+ 00 -> 00 (tried 1 out of 3)
+ 01 -> 04 (tried 3 out of 3)
+ 02 -> 04 (tried 1 out of many: deska, regress)
+ 03 -> 04 (tried 1 out of many: 3d67bb)
+ 04 -> 04 (tried 1 out of many: detailer2)
+
Charset numbers come from the list for \fcharset in the RTF
specification:
http://latex2rtf.sourceforge.net/rtfspec_6.html#rtfspec_10 The charset
01 00
ffff 0000 "DspCell"
- 00 03 80 00 00 00 00 00 00 00 00 00 00
+ 00 03 80 00*10
ffff 0000 "DspNumber"
421:-83360 (-2000) 04 00 00 00 04 00 00
422:cell F40.2 "LogAC"
+
+ZMAW_zaj3:
+
+rec:PVTextStyle
+.. 02 .. 02
+.. c8 .. LM .. RM .. TM .. BM .. .. .. 01 .. yy yy yy yy ww ww .. .. xx xx xx xx .. .. .. .. zz zz zz zz ii uu ss cc cc cc cc 22 "Arial" FF FF FF .. .. .. a7 80 .. 01 .. .. .. .. .. BB BB BB .. SS .. a9 80 .. 01 .. ..
+.. c8 .. 78 .. a0 .. 14 .. 14 .. .. .. 01 .. f3 ff ff ff .. .. .. .. .. .. .. .. .. .. .. .. 90 01 .. .. .. .. .. ee 00 00 00 22 "Arial" .. .. .. .. .. .. a7 80 .. 01 .. .. .. .. .. ff ff ff .. .. .. a9 80 .. 01 .. ..
+.. c8 .. 78 .. a0 .. 14 .. 14 .. .. .. 01 .. f3 ff ff ff .. .. .. .. .. .. .. .. .. .. .. .. 90 01 .. .. .. .. .. ee 00 00 00 22 "Arial" .. .. .. .. .. .. a7 80 .. 01 .. .. .. .. .. ff ff ff .. .. .. a9 80 .. .. .. ..
+.. c8 .. 78 .. a0 .. 14 .. 14 .. .. .. 01 .. f3 ff ff ff .. .. .. .. .. .. .. .. .. .. .. .. 90 01 .. .. .. .. .. ee 00 00 00 22 "Arial" .. .. .. .. .. .. a7 80 .. 01 .. .. .. .. .. ff ff ff .. .. .. a9 80 .. 01 .. 02
+.. c8 .. 78 .. a0 .. 14 .. 14 .. .. .. 01 .. f3 ff ff ff .. .. .. .. .. .. .. .. .. .. .. .. 90 01 .. .. .. .. .. ee 00 00 00 22 "Arial" .. .. .. .. .. .. a7 80 .. 01 .. .. .. .. .. ff ff ff .. .. .. a9 80 .. 02 .. 03
+.. c8 .. 78 .. a0 .. 14 .. 14 .. .. .. 01 .. f3 ff ff ff .. .. .. .. .. .. .. .. .. .. .. .. 90 01 .. .. .. .. .. ee 00 00 00 22 "Arial" .. .. .. .. .. .. a7 80 .. 01 .. .. .. .. .. ff ff ff .. .. .. a9 80 .. 01 .. ..
+.. c8 .. 78 .. a0 .. 14 .. 14 .. .. .. 01 .. f3 ff ff ff .. .. .. .. .. .. .. .. .. .. .. .. 90 01 .. .. .. .. .. ee 00 00 00 22 "Arial" .. .. .. .. .. .. a7 80 .. 01 .. .. .. .. .. ff ff ff .. .. .. a9 80 .. 01 .. ..
+.. c8 .. 68 01 68 01 28 .. 28 .. .. .. 01 .. f3 ff ff ff .. .. .. .. .. .. .. .. .. .. .. .. 90 01 .. .. .. .. .. ee 00 00 00 22 "Arial" .. .. .. .. .. .. .. .. 01 .. .. .. .. .. .. .. 01 .. 01 .. .. .. .. .. .. .. 01
+.. 01 .. .. .. .. .. .. .. 01 .. 01 .. .. .. .. .. .. .. 01 .. .. .. .. .. .. .. .. .. 01 .. .. .. .. .. .. .. 01 .. 01 .. .. .. .. .. .. .. 01 ..
+
+yy: font size, f2ffffff or f3ffffff is normalish, f8ffffff is tiny,
+f0ffffff is big
+ww: something to do with font size or stretch. 01 is normal, 02+ gets weird
+xx: rotation angle
+zz: 400 is normal weight, 700+ is bold
+ii: 1+ is italic
+uu: 1+ is underline
+ss: 1+ is strikethrough
+cc: RTF charset number, e.g. 0 for ANSI, 238 for Polish
+FF: RGB foreground
+BB: RGB background
+SS: shade fraction from 0=unshaded to 0xa=opaque
+LT, RM, TM, BM: margins, 20=1 point
+
+Some confusion on separation, BB and later seem to correspond to the next area
+
+Areas:
+0. title
+1. layers
+2. corner
+3. row heads
+4. column heads
+5. data
+6. caption
+7. footnotes
+
+ rr gg bb 00 00 00 ss 00 01
+ ff 00 ff 00 00 00 01 00 01 00
+ ff 00 ff 00 00 00 01 00 01 00
+ ff 00 ff 00 00 00 01 00 01 00
+ ff 00 ff 00 00 00 01 00 00 00
+ 00 00 00 00 00 00 01 00
+ ff 00 ff 00 00 00 01 00 01 00
+ ff 00 ff 00 00 00 01 00
+
+rr gg bb: stroke color
+ss: style, 0=thin, 1=normal, 2=thick, 3=very thick, otherwise weird
+
+Borders:
+- horizontal category columns
+- vertical category columns
+...
+- left inner frame
+- right inner frame
+- top inner frame
+- bottom inner frame
+- left data area
+- top data area
+
+
+..
+01 .. ff .. ff .. .. .. .. ..
+.. .. .. .. .. .. 03 80 ..
+01 .. ff .. ff .. .. .. .. ..
+01 .. ff .. ff .. .. .. .. ..
+01 .. ff .. ff .. .. .. .. ..
+01 .. ff .. ff .. .. .. .. ..
+
+..
+01 .. .. .. .. .. .. .. .. ..
+.. .. .. .. .. .. 03 80 ..
+01 .. .. .. .. .. .. .. .. .. .. ..
+01 .. .. .. .. .. .. .. .. .. .. ..
+
+..
+01 .. 80 80 80 .. .. .. 01 ..
+01 .. 80 80 80 .. .. .. 01 ..
+01 .. 80 80 80 .. .. .. .. ..
+01 .. 80 80 80 .. .. .. .. ..
+ba 80 ..
+01 .. 80 80 80 .. .. .. 01 ..
+01 .. 80 80 80 .. .. .. 01 ..
+01 .. 80 80 80 .. .. .. .. ..
+01 .. 80 80 80 .. .. .. .. ..
+
+class {00000319-0000-0000-c000-000000000046}: Enhanced Metafile
+ For these, dropping the first 4 bytes of Embedding*/CONTENTS file
+ yields an EMF file that the printemf program can dissect.
+
+class {62078ae0-e4fe-11cd-838d-0000c0f17248}:
+ harder to pin down what's in these
+
+view-spo can Edit|copy notes and tables for pasting into other applications
+
+rigger: contains working graph!
+
+correspondence:
+ 1/01 80 ? "NavRoot"
+ 3/03 80 -> "DspSimpleText"
+ 5/05 80 -> "DspString" 01 02 28 (00|05) 00 01 b"string"
+ 7/07 80 -> "NavTreeViewItem"
+ 9/09 80 -> "NavLog"
+11/0b 80 ? "NavHead"
+13/0d 80 ? "NavTitle"
+15/0f 80 ???
+17/11 80 ???
+19/13 80 ???
+21/15 80 ???
+24 18 80 -> "NavNote"
+29 1d 80 -> "PTPivotController"
+31 1f 80 -> "PTPivotView"
+33/21 80 -> "PMPivotModel"
+35/23 80 -> "NDimensional__DspCell"
+37/25 80 -> "IndexedCollection"
+39/27 80 -> "DspCell"
+41/29 80 ? "DspNumber"
+ /50 80 -> "PMPivotItemTree"
+ /52 80 -> "AbstractTreeBranch"
+ /54 80 -> "PMModelItemInfo"
+
+
+When the top-level "Output" node is selected for save:
+ 04 i0
+ "SPSS Output Document"
+ i1 63
+ ffff 0000 "NavRoot" 02 00*32
+ ffff 0000 "DspSimpleText" 00*10
+ ffff 0000 "DspString" 01 02 28 00 00 01 b"Output"
+ ffff 0000 "NavTreeViewItem" 00 i0 02 00 01 00*9 i1
+00c0 (i0 | i24) (i24 | i-40) (i0 | i40 | i-40) (i40 | i-34)
+00d0 (i1048 | some other 3-hex-digit number | i0)
+00d4 (i0 | some 3 to 4-hex-digit number | i-40)
+00d8 00*5
+00dd (i8500 i11000 | i11000 i8500)
+00e5 (s1 | s9) (s1 | s7 | s15) (s1 | s2)
+00eb i1270*4
+00fb s0 i240 s?? s1 b"(Continued)" 01 01 00*3 byte 00*3
+0116 w"{\rtf... pagetitle}"
+01fd 01 01 00*3
+0202 w"{\rtf... page number}"
+02e9 00 short s2
+
+(This is a valid spot for the file to contain 00000000 then eof)
+
+02ee ffff 0000 "NavLog" 02 i0*2 i24
+0307 (i0 | i-40) (i691 | i987) (2-3 digit negative int) i1
+0317 i0
+0318 03 80 00*10
+0324 05 80 01 02 28 05 00 01 b"Log"
+0333 07 80 00 i2 0a 00 01 00*9 i1 00*2 01 01 (f3|f4) ff ff ff 00*4
+0357 00*8 90 01 00*9 (22|31)
+036b 32-bytes of null-padded font name, e.g. "Courier New".
+ Sometimes garbage after the first null.
+038b (i80 | i132) 00*8 i1
+038f 00*8 i1
+039b w"{\rtf ... SPSS syntax...}"
+
+Almost past SPSS syntax (only the } included):
+0000 '}' 00
+0002 ffff 0000 "NavHead" 02
+0010 00*24 i1 i0
+0030 03 80 00 00 00 00 00 00 00 00 00 00 05 80 01 02
+0040 28 05 00 01
+0044 b"Cluster|Crosstabs|..."
+
+Just past the string:
+0000 07 80 00 00 00 00 00 0f 00 01 00 00 00 00 00 00
+0010 00 00 00 01 00 00 00 00 00
+0019 b"Cluster|Crosstabs|..."
+
+Just past the string again:
+0000 00*3
+0003 ffff 0000 "NavTitle"
+0011 65 02 00 00 00 00 00 00 00 00 18 00 00 00 byte byte
+0020 ff ff 00 04 00 00 byte byte
+0028 ff ff 02 00 00 00 01 00 00 00 03 80 00*10
+003e 05 80 01 02 28 00 00 01 b"Title"
+004c 07 80 00 08
+0050 00 00 00 14 00 01 00*9 01
+0060 00*5
+0065 b"Cluster|Crosstabs|..."
+
+Just past the third string:
+0000 01 01 ed ff ff ff 00 00 00 00 00 00 00 00 00 00
+0010 00 00 bc 02 00 00 00 00 00 00 00 00 00 22
+001e 32-bytes of buggy zero-padded string "Arial"
+003e 50 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00
+004e w"{\rtf...}"
+
+Almost past the RTF (only } included):
+0000 '}' 00
+0002 ffff 0000 "NavNote"
+0010 02 00 00 00 00 00 00 00 00 18 00 00 00 (i0 | i-40)
+0020 int int i2 i1
+0030 03 80 00*10
+003c 05 80 01 02 28 05 00 01 b"Notes"
+004a 07 80 00 i7 19 00 01 00 00*2 01 00*5 01 00*5
+0063 b"Cluster|Crosstabs|..."
+
+Just past the fourth string:
+0000 01
+
+0001 ffff 0000 "PTPivotController"
+0018 02
+0019 byte*8 # weird ASCIIish garbage
+0021 i100*4
+
+0031 ffff 0000 "PVPivotView"
+0042 05 00 00 00 00
+
+0047 ffff 0000 "PMPivotModel"
+0059 03
+
+005a ffff 0000 "NDimensional__DspCell"
+0075 00 01 00 00 00
+
+007a ffff 0000 "IndexedCollection"
+0091 00 byte 00 00 00 01 00
+
+0098 ffff 0000 "DspCell"
+00a6 00
+00a7 03 80 00*10
+
+Fork: cell contains number ("as-number"):
+00b2 ffff 0000 "DspNumber"
+00c1 01 00 14 16 # 00 14 16 is DATETIME20.0
+00c5 80 02
+00c7 double # seconds since 1582...
+00cf b"16-APR-2007 15:20:00" # or whatever
+00e4 27
+00e5 80 00 03 80 00 00 00 00 00 00 00 00 00 00 05
+00f4 80 01 02 28 05 00 01 01 20
+ # Some files have extra 00 00 here
+ # but we're only considering as-number-nozeros
+00fd 27 80 00
+0100 03 80 00*10
+010e 05 80 01 02 28 05 00 01
+0114 # Either b"filename" with a length < 255
+ # or ff "filename" with a length >= 255
+
+as-number-nozeros, after filename:
+0000 27 80 00
+0003 03 80 00*10 05
+0010 80 01 02 28 05 00 01 b"<none> or DataSet1 or whatever"
+
+as-number-nozeros, after dataset name:
+0000 27 80 00
+0003 03 80 00*10 05
+0010 80 01 02 28 05 00 01 b"<none>"
+
+# Some files have extra 00*8 here, we skip it:
+0000 27 80 00
+0003 03 80 00*5 (00|10) 00*4 05
+0010 80 01 02 28 05 00 01 b"<none> or DATASET..."
+
+as-number-nozeros-majority, after dataset name:
+0000 27 80 00 03 80 00*10 05 80 01 02 28 05 00 01 b"<none>"
+001e 27 80 00 03 80 00*10 2a 80 01 00 28 05 80 02 100.0 b"100"
+ # Followed by 6 optional zeros
+
+as-number-nozeros-majority, after optional zeros:
+0000 27 80 00 03 80 00*10 05 80 01 02 28 05 00 01 b"User-defined missing values..."
+ ^ sixth 00 may be 10 instead
+
+as-number-nozeros-majority, after "User-defined missing values...":
+0000 27 80 00 03 80 00*10 (05|2a) 80 01 02 28 05 00 01 b"Statistics are based on..."
+
+as-number-nozeros-majority, after "Statistics are based on...":
+0000 00 00
+0002 27 80 00 03 80 00*10 05 80 01 02 28 05 00 01 b"syntax fragment"
+ ^ sixth 00 may be 10 instead
+
+as-number-nozeros-majority, after syntax fragment:
+0000 27 80 00 03 80 00*10 2a 80 01 02 0d 15 80 02 double b"0:00:00.02"
+selecting for the ones that include Processor Time instead of RAM:
+002a 27 80 00 03 80 00*10 2a 80 01 02 0d 15 80 02 double b"0:00:00.03"
+0054 01 00 b"Notes" 00*4
+0060 b"Cluster_Notes"
+
+processor-time, after previous string:
+0000 00 01 00 00 00 01 00
+
+0007 ffff 0000 "PMPivotItemTree" 00
+001d ffff 0000 "AbstractTreeBranch" 00
+0036 ffff 0000 "PMModelItemInfo"
+ 00*9 byte*3 0e 00 03 80 00*10
+0065 05 80 01 02 28 05 00 01 b"Contents" i7
+ 52 80 00
+ 54 80 00 00*9 07 00 74 0e 00 03 80 00*10
+0099 05 80 01 02 28 05 00 01 b"Output Created" i0
+ 52 80 00
+ 54 80 00 01 00*7 08 00 74 0e 00 03 80 00*10
+00d3 05 80 01 02 28 05 00 01 b"Comments" i0
+00e8 52 80 00
+ 54 80 00*9 09 00 74 0e 00 03 80 00*10
+ 05 80 01 02 28 05 00 01 b"Input" i6
+ 52 80 00
+ 54 80 00 02 00*7 0a 00 74 0e 00 03 80 00*10
+0138 05 80 01 02 28 05 00 01 b"Data" i0
+ 52 80 00
+ 54 80 00 03 00*12 03 80 00*10
+ 05 80 01 02 28 05 00 01 b"Active Dataset" i0
+0183 52 80 00
+ 54 80 00 04 00*7 0e 00 74 0e 00 03 80 00*9
+01a2 05 80 01 02 28 05 00 01 b"Filter" i0
+01b5 52 80 00
+ 54 80 00 05 00*7 11 00 74 0e 00 03 80 00*10
+01d4 05 80 01 02 28 05 00 01 b"Weight" i0
+01e7 52 80 00
+ 54 80 00 06 00 00
+01f0 00 00 00 00 00 12 00 74 0e 00 03 80 00 00 00 00
+0200 00 00 00 00 00 00 05 80 01 02 28 05 00 01 b"Split File"
+0219 00 00 00 00 52 80 00
+0220 54 80 00 07 00 00 00 00 00 00 00 13 00 74 0e 00
+0230 03 80 00 00 00 00 00 00 00 00 00 00 05 80 01 02
+0240 28 05 00 01 b"N of Rows in Working Data File"
+0263 00 00 00 00 52 80 00 54 80 00 00 00 00
+0270 00 00 00 00 00 byte*2 74 0e 00 03 80 00 00 00 00
+0280 00 00 00 00 00 00 05 80 01 02 28 05 00 01
+028e b"Missing Value Handling"
+02a5 02 00 00 00 52 80 00 54 80 00 08
+02b0 00 00 00 00 00 00 00 byte*2 74 0e 00 03 80 00 00
+02c0 00 00 00 00 00 00 00 00 05 80 01 02 28 05 00 01
+02d0 b"Definition of Missing"
+02e6 00 00 00 00 52 80 00 54 80 00
+02f0 09 00 00 00 00 00 00 00 byte*2 74 0e 00 03 80 00
+0300 00 00 00 00 00 00 00 00 00 05 80 01 02 28 05 00
+0310 01 b"Cases Used" 00*4
+0320 52 80 00 54 80 00 0a 00 00 00 00 00 00 00 17 00
+0330 74 0e 00 03 80 00 00 00 00 00 00 00 00 00 00 05
+0340 80 01 02 28 05 00 01 b"Weight Handling"
+0357 00 00 00 00 52 80 00 54 80
+0360 00 0b 00 00 00 00 00 00 00 18 00 74 0e 00 03 80
+0370 00 00 00 00 00 00 00 00 00 00 05 80 01 02 28 05
+0380 00 01 b"Syntax" 00 00 00 00 52 80 00
+0390 54 80 00 00 00 00 00 00 00 00 00 byte*2 74 0e 00
+03a0 03 80 00 00 00 00 00 00 00 00 00 00 05 80 01 02
+03b0 28 05 00 01 b"Resources" 02 00
+03c0 00 00 52 80 00 54 80 00 0c 00 00 00 00 00 00 00
+03d0 1b 00 74 0e 00 03 80 00 00 00 00 00 00 00 00 00
+03e0 00 05 80 01 02 28 05 00 01 b"Elapsed Time"
+03f6 00 00 00 00 52 80 00 54 80 00
+0400 0d 00 00 00 00 00 00 00 00 00 00 00 00 03 80 00
+0410 00 00 00 00 00 00 00 00 00 05 80 01 02 28 05 00
+0420 01 b"Processor Time"
+0430 00 00 00 00 00 00 00 00 00 00 0e 00 00 00 01 00
+0440 58 00 5c 00 64 00 68 00 6c 00 70 00 74 00 78 00
+0450 80 00 84 00 88 00 8c 00 94 00 98 00 00 0e 00 00
+0460 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 03
+0470 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07
+0480 00 00 00 08 00 00 00 09 00 00 00 0a 00 00 00 0b
+0490 00 00 00 0c 00 00 00 0d 00 00 00 00 00 00 00 00
+04a0 01 00 00 11 00 00 00 00 00 04 00 00 00 e1 00 00
+04b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+04c0 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00
+04d0 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00
+04e0 00 01 00 ff ff 00 00 b"PVViewDimension"
+04f8 00 51 00 00 00 00 00 00
+0500 00 00 00 00 0e 00 00 00 00 00 69 00 00 00 54 00
+0510 00 00 4b 00 00 00 63 00 00 00 4b 00 00 00 4b 00
+0520 00 00 4b 00 00 00 7d 00 00 00 87 00 00 00 5c 00
+0530 00 00 72 00 00 00 4b 00 00 00 63 00 00 00 6f 00
+0540 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00
+0550 00 87 00 00 00 00 03 80 00 00 00 00 00 00 00 00
+0560 00 00 05 80 01 02 28 05 00 01 b"Notes"
+0570 00 03 80 00 00 00 00 00 00 00 00 00 00 05 80 01
+0580 02 28 00 00 01 00 00 00 00 00 00 00 00 00 03 80
+0590 00 00 00 00 00 00 00 00 00 00 05 80 01 02 28 00
+05a0 00 01 00
+
+05a3 ffff 0000 "PTTableLook"
+05b4 02 02 00 00 00 00 00 00 00 36 00 00
+05c0 00 12 00 00 00
+
+05c5 ffff 0000 "PVSeparatorStyle"
+05db 00 01 00 00 00
+05e0 00 00 00 00 00 00 00 00 00 00 00 00 a6 80 00 01 |................|
+05f0 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 |................|
+0600 00 00 00 01 00 00 00 00 00 00 00 00 00 01 00 00 |................|
+0610 00 00 00 00 00 00 00
+
+0607 ffff 0000 "PVCellStyle"
+0628 00 01 00 00 00 00 00 ff
+
+0630 ffff 0000 00
+
+0637 ffff 0000 "PVTextStyle"
+0646 00 02 00 02 00 c8 00 78 00 a0
+0650 00 14 00 78 00 00 00 01 00 f3 ff ff ff 00 00 00
+0660 00 00 00 00 00 00 00 00 00 bc 02 00 00 00 00 00
+0670 00 00 00 00 22 b"Arial" 00 00 00 00 00
+0680 00 a9 80 00 01 00 00 00 00 00 ff ff ff 00 00 00
+0690 ab 80 00 01 00 00 00 c8 00 78 00 a0 00 14 00 14
+06a0 00 00 00 01 00 f3 ff ff ff 00 00 00 00 00 00 00
+06b0 00 00 00 00 00 90 01 00 00 00 00 00 00 00 00 00
+06c0 22 b"Arial" 00 00 00 00 00 00 a9 80 00
+06d0 01 00 00 00 00 00 ff ff ff 00 00 00 ab 80 00 01
+06e0 00 00 00 c8 00 78 00 a0 00 14 00 14 00 00 00 01
+06f0 00 f3 ff ff ff 00 00 00 00 00 00 00 00 00 00 00
+0700 00 90 01 00 00 00 00 00 00 00 00 00 22 b"Arial"
+0713 00 00 00 00 00 00 a9 80 00 01 00 00 00
+0720 00 00 ff ff ff 00 00 00 ab 80 00 00 00 00 00 c8
+0730 00 78 00 a0 00 14 00 14 00 00 00 01 00 f3 ff ff
+0740 ff 00 00 00 00 00 00 00 00 00 00 00 00 90 01 00
+0750 00 00 00 00 00 00 00 00 22 b"Arial" 00
+0760 00 00 00 00 00 a9 80 00 01 00 00 00 00 00 ff ff
+0770 ff 00 00 00 ab 80 00 01 00 02 00 c8 00 78 00 a0
+0780 00 14 00 14 00 00 00 01 00 f3 ff ff ff 00 00 00
+0790 00 00 00 00 00 00 00 00 00 90 01 00 00 00 00 00
+07a0 00 00 00 00 22 b"Arial" 00 00 00 00 00
+07b0 00 a9 80 00 01 00 00 00 00 00 ff ff ff 00 00 00
+07c0 ab 80 00 02 00 03 00 c8 00 78 00 a0 00 14 00 14
+07d0 00 00 00 01 00 f3 ff ff ff 00 00 00 00 00 00 00
+07e0 00 00 00 00 00 90 01 00 00 00 00 00 00 00 00 00
+07f0 22 b"Arial" 00 00 00 00 00 00 a9 80 00
+0800 01 00 00 00 00 00 ff ff ff 00 00 00 ab 80 00 01
+0810 00 00 00 c8 00 78 00 a0 00 14 00 14 00 00 00 01
+0820 00 f3 ff ff ff 00 00 00 00 00 00 00 00 00 00 00
+0830 00 90 01 00 00 00 00 00 00 00 00 00 22 b"Arial"
+0843 00 00 00 00 00 00 a9 80 00 01 00 00 00
+0850 00 00 ff ff ff 00 00 00 ab 80 00 01 00 00 00 c8
+0860 00 68 01 68 01 28 00 28 00 00 00 01 00 f3 ff ff
+0870 ff 00 00 00 00 00 00 00 00 00 00 00 00 90 01 00
+0880 00 00 00 00 00 00 00 00 22 b"Arial" 00
+0890 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01
+08a0 00 01 00 00 00 00 00 00 00 01 00 01 00 00 00 00
+08b0 00 00 00 01 00 01 00 00 00 00 00 00 00 01 00 00
+08c0 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 01
+08d0 00 01 00 00 00 00 00 00 00 01 00 b"(cont.)"
+08e3 24 00 00 00 48 00 00 00 24 00 00 00 78
+08f0 00 00 00 00 00 00 00 00 00 00 00
+
+08fb ffff 0000 "PVPrintManager" 02
+0910 1e 00 02 00 00 00 03 00 00 00 01 00 00 00 00 00
+0920 00 00 00 00 00 00 00
+
+0927 ffff 0000 "NavText"
+0934 02 00 00 00 00 00 00 00 00 18 00 00
+0940 00 byte*2 ff ff byte*2 00 00 byte*2 ff ff 02 00 00
+0950 00 01 00 00 00 03 80 00 00 00 00 00 00 00 00 00
+0960 00 05 80 01 02 28 05 00 01 b"Active Dataset"
+0978 07 80 00 10 00 00 00 be
+0980 00 01 00 00 00 00 00 00 00 00 00 01 00 00 00 00
+0990 00 b"Cluster etc." 07 43 6c 75 73 74 65 72 01 01 f3 ff ff ff 00
+0990 00 0b 46 72 65 71 75 65 6e 63 69 65 73 01 01 f3
+
+Just past "Cluster":
+0000 01 01 (f3|f4) ff ff ff 00 00 00 00 00 00 00 00 00 00
+0010 00 00 90 01 00 00 00 00 00 00 00 00 00 (22|31)
+001e 32-bytes of null-padded font name, e.g. "Courier New".
+ Sometimes garbage after the first null.
+003e byte 00*11 w"{\rtf... giving filesystem path}"
+
+Almost past RTF (just trailing }):
+0000 '}' ffff 0000 "NavPivot" 02 int int i24 int
+0020 int int i2 i1
+0030 03 80 00*10 05 80 01 02
+0040 28 05 00 01 b"Statistics etc."
+
+Just past "Statistics":
+0000 07 80 00 0c 00 00 00 c3 00 01 00 00 00 00 00 00
+0010 00 00 00 01 00 00 00 00 00 b"Cluster etc."
+
+Just past "Cluster", using boot/Contents as exemplary:
+0000 01
+0001 1d 80 02 i0*2 i100*4 # 1d 80 corresponds to "PTPivotController"
+001c 1f 80 05 00*4 # 1f 80 corresponds to "PTPivotView"
+0023 21 80 03 # 21 80 corresponds to "PMPivotModel"
+0026 23 80 00 (02|03) 00 00 00 # 23 80 corresponds to "NDimensional__DspCell"
+002d 25 80 00 i100 01 00 # 25 80 corresponds to "IndexedCollection"
+0036 25 80 00 i100 01 00
+003f 27 80 00 03 80 00*10 2a 80 01 F40.0 80 02 100.0 b"100"
+0062 27 80 00 03 80 00*10 2a 80 01 F40.0 80 02 100.0 b"100"
+ ...repeats...
+0f03 25 80 00 6c 00 00 00 01 00
+0f0c 27 80 00 03 80 00*10 2a 80 01 F40.0 80 02 0.0 b"0"
+ ...repeats...
+1cf8 25 80 00 6c 00 00 00 01 00
+1d01 27 80 00 03 80 00*10 2a 80 01 F40.8 1
+
+Notes
+Output Created 16-JAN-2008 02:45:55
+Comments
+Input Data \\Ugly\amead\consulting\center\Dell\Exams\RE\analyses\Blended15\pilotdata-2008-01-15.csv
+ Active Dataset raw1
+ Filter <none>
+ Weight <none>
+ Split File <none>
+ N of Rows in Working Data File 366
+Missing Value Handling Definition of Missing User-defined missing values are treated as missing.
+ Cases Used Statistics are based on all cases with valid data.
+Syntax FREQUENCIES\r VARIABLES=exam_id exam_name restarts\r /ORDER= ANALYSIS .\r
+Resources Elapsed Time 0:00:00.02
+ Processor Time 0:00:00.03