From 6fbf3ec9ce0176ef805a18086b4cfe66df9cfbba Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 23 Jun 2020 02:25:08 +0000 Subject: [PATCH] learned some things about spos --- dump-spo2.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ spo-notes | 46 +++++++++++++++++------------ 2 files changed, 111 insertions(+), 19 deletions(-) diff --git a/dump-spo2.c b/dump-spo2.c index 3367163275..d50d861fa4 100644 --- a/dump-spo2.c +++ b/dump-spo2.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -257,6 +258,20 @@ get_string1(void) 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) { @@ -266,6 +281,20 @@ 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) { @@ -406,6 +435,40 @@ format_name (int format, char *buf) } } +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[]) @@ -463,5 +526,26 @@ 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; } diff --git a/spo-notes b/spo-notes index 30132d6f5c..93682571b9 100644 --- a/spo-notes +++ b/spo-notes @@ -692,20 +692,32 @@ correspondence: 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}" @@ -718,7 +730,9 @@ When the top-level "Output" node is selected for save: 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. @@ -728,16 +742,14 @@ When the top-level "Output" node is selected for save: 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 @@ -746,10 +758,7 @@ Just past the string again: 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 @@ -765,8 +774,7 @@ Almost past the RTF (only } included): 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 -- 2.30.2