#include <errno.h>
#include <fcntl.h>
#include <float.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
return s;
}
+static void
+match_string1_assert(const char *exp, const char *where)
+{
+ int start = pos;
+ char *act = get_string1();
+ if (strcmp(act, exp))
+ {
+ fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
+ where, start, exp, act);
+ exit(1);
+ }
+}
+#define match_string1_assert(x) match_string1_assert(x, WHERE)
+
static char *
get_string2(void)
{
return s;
}
+static void
+match_string2_assert(const char *exp, const char *where)
+{
+ int start = pos;
+ char *act = get_string2();
+ if (strcmp(act, exp))
+ {
+ fprintf(stderr, "%s: 0x%x: expected \"%s\", got \"%s\"\n",
+ where, start, exp, act);
+ exit(1);
+ }
+}
+#define match_string2_assert(x) match_string2_assert(x, WHERE)
+
static char *
get_string(const char *where)
{
}
}
+static void
+parse_heading(const char *name)
+{
+ match_u16_assert(0xffff);
+ match_u16_assert(0);
+ match_string2_assert(name);
+}
+
+static void
+match_zeros_assert(int count)
+{
+ for (int i = 0; i < count; i++)
+ if (data[pos + i])
+ {
+ fprintf (stderr,
+ "%#x: expected %d zeros here but offset %d is %#"PRIx8"\n",
+ pos, count, i, data[pos + i]);
+ exit (1);
+ }
+ pos += count;
+}
+
+static void
+parse_DspString(void)
+{
+ match_byte_assert(1);
+ match_byte_assert(2);
+ match_byte_assert(40);
+ if (!match_byte(0))
+ match_byte_assert(5);
+ match_byte_assert(0);
+ match_byte_assert(1);
+ printf ("DspString(\"%s\")\n", get_string1());
+}
int
main(int argc, char *argv[])
setvbuf (stdout, NULL, _IOLBF, 0);
+ match_byte_assert(4);
+ match_u32_assert(0);
+ match_string1_assert("SPSS Output Document");
+ match_u32_assert(1);
+ match_byte_assert(0x63);
+
+ parse_heading("NavRoot");
+ match_byte_assert(2);
+ match_zeros_assert(32);
+
+ parse_heading("DspSimpleText");
+ match_zeros_assert(10);
+
+ parse_heading("DspString");
+ parse_DspString();
+
+ parse_heading("NavTreeViewItem");
+
+
+ printf ("%#x: end of successful parse\n", pos);
+
return 0;
}
When the top-level "Output" node is selected for save:
04 i0
- "SPSS Output Document"
+ b"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
+ 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
+00dd i8500 # paper width in 1000/inch (i11000 for landscape)
+00e1 i11000 # paper length in 1000/inch (i8500 for landscape)
+00e5 s1 # letter paper (5=legal, 9=A4, etc.)
+00e7 s15 # s1, s7 also seen
+00e9 s1 # portrait; s2 = landscape
+00eb i1270 # left margin in 2540/inch, e.g. 1270 = .5 inch
+00ef i1270 # top margin in 2540/inch
+00f3 i1270 # right margin
+00f7 i1270 # bottom margin
+00fb s0
+00fd s240 # object spacing in 1440/inch, e.g. 240 = 12 pt
+00ff s0 # charts: 0=asis, 1=full page, 2=half, 03=quarter
+0101 s??
+0103 s1 # starting page number
+0105 b"(Continued)" 01 01 00*3 byte 00*3
0116 w"{\rtf... pagetitle}"
01fd 01 01 00*3
0202 w"{\rtf... page number}"
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
+
+0333 07 80 00 02 00 00 00 0a 00 01 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00
+0347 00*2 01 01 (i-13 | i-12) i0
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.
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|..."
+0030 03 80 00 00 00 00 00 00 00 00 00 00
+ 05 80 01 02 28 05 00 01 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|..."
+0000 07 80 00 00 00 00 00 0f 00 01 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 b"Cluster|Crosstabs|..."
Just past the string again:
0000 00*3
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|..."
+004c 07 80 00 08 00 00 00 14 00 01 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 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
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|..."
+004a 07 80 00 07 00 00 00 19 00 01 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 b"Cluster|Crosstabs|..."
Just past the fourth string:
0000 01