completed all the tests!
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 6 Jul 2025 22:23:19 +0000 (15:23 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 6 Jul 2025 22:23:19 +0000 (15:23 -0700)
38 files changed:
rust/doc/src/system-file.md
rust/pspp/src/format/display/mod.rs
rust/pspp/src/format/mod.rs
rust/pspp/src/sys/raw.rs
rust/pspp/src/sys/testdata/partial_compressed_data_record.expected
rust/pspp/src/sys/testdata/partial_data_record_between_variables.expected
rust/pspp/src/sys/testdata/partial_data_record_within_long_string.expected
rust/pspp/src/sys/testdata/unspecified_number_of_variable_positions.expected
rust/pspp/src/sys/testdata/variable_labels_and_missing_values.expected
rust/pspp/src/sys/testdata/wrong_variable_positions_but_v13.expected
rust/pspp/src/sys/testdata/zcompressed_data.expected
rust/pspp/src/sys/testdata/zcompressed_data_bad_zheader_ofs.expected
rust/pspp/src/sys/testdata/zcompressed_data_bad_zheader_ofs.sack
rust/pspp/src/sys/testdata/zcompressed_data_bad_ztrailer_ofs.expected
rust/pspp/src/sys/testdata/zcompressed_data_bad_ztrailer_ofs.sack
rust/pspp/src/sys/testdata/zcompressed_data_compressed_sizes_don_t_add_up.expected
rust/pspp/src/sys/testdata/zcompressed_data_compressed_sizes_don_t_add_up.sack
rust/pspp/src/sys/testdata/zcompressed_data_compressed_sizes_dont_add_up.expected
rust/pspp/src/sys/testdata/zcompressed_data_compression_expands_data_too_much.expected
rust/pspp/src/sys/testdata/zcompressed_data_compression_expands_data_too_much.sack
rust/pspp/src/sys/testdata/zcompressed_data_invalid_ztrailer_len.expected
rust/pspp/src/sys/testdata/zcompressed_data_invalid_ztrailer_len.sack
rust/pspp/src/sys/testdata/zcompressed_data_uncompressed_size_block_size.expected
rust/pspp/src/sys/testdata/zcompressed_data_uncompressed_size_block_size.sack
rust/pspp/src/sys/testdata/zcompressed_data_wrong_block_size.expected
rust/pspp/src/sys/testdata/zcompressed_data_wrong_block_size.sack
rust/pspp/src/sys/testdata/zcompressed_data_wrong_compressed_ofs.expected
rust/pspp/src/sys/testdata/zcompressed_data_wrong_compressed_ofs.sack
rust/pspp/src/sys/testdata/zcompressed_data_wrong_n_blocks.expected
rust/pspp/src/sys/testdata/zcompressed_data_wrong_n_blocks.sack
rust/pspp/src/sys/testdata/zcompressed_data_wrong_uncompressed_ofs.expected
rust/pspp/src/sys/testdata/zcompressed_data_wrong_uncompressed_ofs.sack
rust/pspp/src/sys/testdata/zcompressed_data_wrong_ztrailer_bias.expected
rust/pspp/src/sys/testdata/zcompressed_data_wrong_ztrailer_bias.sack
rust/pspp/src/sys/testdata/zcompressed_data_wrong_ztrailer_len.expected
rust/pspp/src/sys/testdata/zcompressed_data_wrong_ztrailer_len.sack
rust/pspp/src/sys/testdata/zcompressed_data_wrong_ztrailer_zero.expected
rust/pspp/src/sys/testdata/zcompressed_data_wrong_ztrailer_zero.sack

index 8fdab46ab5368381f3196ebcddbc5b3f32d7f197..06767966cef655cddfb6323954d9542bbfe10eed 100644 (file)
@@ -1834,8 +1834,10 @@ case.  The format of the data record varies depending on the value of
 
   - `int64 zheader_ofs;`
 
-    The offset, in bytes, of the beginning of this structure
-    within the system file.
+    The offset, in bytes, of the beginning of this structure within
+    the system file.  A reader does not need to use this, so it can
+    ignore it (PSPP issues a warning if it does not match its own
+    offset).
 
   - `int64 ztrailer_ofs;`
 
index 6fcce1791b3821087c57f3b5916cd2fd3d9cb8b7..b531099e531835239b74b30a674e13993bad1520 100644 (file)
@@ -49,7 +49,7 @@ impl DisplayPlain for f64 {
     }
 }
 
-pub struct DisplayPlainF64(f64);
+pub struct DisplayPlainF64(pub f64);
 
 impl Display for DisplayPlainF64 {
     fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
index 945cfa6c60cc95cf5f69194d17a04ee9338ea238..508d0d88f7c2ad64032f05edb4d7162971b31f1f 100644 (file)
@@ -18,7 +18,7 @@ use crate::{
 
 mod display;
 mod parse;
-pub use display::{DisplayDatum, DisplayPlain};
+pub use display::{DisplayDatum, DisplayPlain, DisplayPlainF64};
 
 #[derive(Clone, ThisError, Debug, PartialEq, Eq)]
 pub enum Error {
index f81a671ea634c7a80cd89d703cc2b5ba2ed1713b..44c40c45703b327b60715405952624d365b3f15f 100644 (file)
@@ -1,7 +1,7 @@
 use crate::{
     dictionary::{Attributes, Datum, VarWidth},
     endian::{Endian, Parse, ToBytes},
-    format::DisplayPlain,
+    format::{DisplayPlain, DisplayPlainF64},
     identifier::{Error as IdError, Identifier},
     sys::encoding::{default_encoding, get_encoding, Error as EncodingError},
 };
@@ -94,9 +94,13 @@ pub enum Error {
     },
 
     #[error(
-        "Unexpected end of file at offset {offset:#x}, {case_ofs} bytes into a compressed case."
+        "Unexpected end of file at offset {offset:#x}, {case_ofs} bytes and {n_chunks} compression chunks into a compressed case."
     )]
-    EofInCompressedCase { offset: u64, case_ofs: u64 },
+    EofInCompressedCase {
+        offset: u64,
+        case_ofs: u64,
+        n_chunks: usize,
+    },
 
     #[error("Data ends at offset {offset:#x}, {case_ofs} bytes into a compressed case.")]
     PartialCompressedCase { offset: u64, case_ofs: u64 },
@@ -107,6 +111,27 @@ pub enum Error {
     #[error("At {case_ofs} bytes into compressed case starting at offset {offset:#x}, a number was found where a string was expected.")]
     CompressedStringExpected { offset: u64, case_ofs: u64 },
 
+    #[error("Impossible ztrailer_offset {0:#x}.")]
+    ImpossibleZTrailerOffset(u64),
+
+    #[error("ZLIB header's zlib_offset is {actual:#x} instead of expected {expected:#x}.")]
+    UnexpectedZHeaderOffset { actual: u64, expected: u64 },
+
+    #[error("Invalid ZLIB trailer length {0}.")]
+    InvalidZTrailerLength(u64),
+
+    #[error(
+        "ZLIB trailer bias {actual} is not {} as expected from file header bias.",
+        DisplayPlainF64(*expected)
+    )]
+    WrongZlibTrailerBias { actual: i64, expected: f64 },
+
+    #[error("ZLIB trailer \"zero\" field has nonzero value {0}.")]
+    WrongZlibTrailerZero(u64),
+
+    #[error("ZLIB trailer specifies unexpected {0}-byte block size.")]
+    WrongZlibTrailerBlockSize(u32),
+
     #[error("Block count {n_blocks} in ZLIB trailer at offset {offset:#x} differs from expected block count {expected_n_blocks} calculated from trailer length {ztrailer_len}.")]
     BadZlibTrailerNBlocks {
         offset: u64,
@@ -115,6 +140,30 @@ pub enum Error {
         ztrailer_len: u64,
     },
 
+    #[error("ZLIB block descriptor {index} reported uncompressed data offset {actual:#x}, when {expected:#x} was expected.")]
+    ZlibTrailerBlockWrongUncmpOfs {
+        index: usize,
+        actual: u64,
+        expected: u64,
+    },
+
+    #[error("ZLIB block descriptor {index} reported compressed data offset {actual:#x}, when {expected:#x} was expected.")]
+    ZlibTrailerBlockWrongCmpOfs {
+        index: usize,
+        actual: u64,
+        expected: u64,
+    },
+
+    #[error("ZLIB block descriptor {index} reports compressed size {compressed_size} and uncompressed size {uncompressed_size}.")]
+    ZlibExpansion {
+        index: usize,
+        compressed_size: u32,
+        uncompressed_size: u32,
+    },
+
+    #[error("ZLIB trailer is at offset {zheader:#x} but {descriptors:#x} would be expected from block descriptors.")]
+    ZlibTrailerOffsetInconsistency { descriptors: u64, zheader: u64 },
+
     #[error("File metadata says it contains {expected} cases, but {actual} cases were read.")]
     WrongNumberOfCases { expected: u64, actual: u64 },
 
@@ -280,6 +329,20 @@ pub enum Warning {
     #[error("Compression bias is {0} instead of the usual values of 0 or 100.")]
     UnexpectedBias(f64),
 
+    #[error("ZLIB block descriptor {index} reported block size {actual:#x}, when {expected:#x} was expected.")]
+    ZlibTrailerBlockWrongSize {
+        index: usize,
+        actual: u32,
+        expected: u32,
+    },
+
+    #[error("ZLIB block descriptor {index} reported block size {actual:#x}, when at most {max_expected:#x} was expected.")]
+    ZlibTrailerBlockTooBig {
+        index: usize,
+        actual: u32,
+        max_expected: u32,
+    },
+
     #[error("Details TBD (raw)")]
     TBD,
 }
@@ -854,28 +917,31 @@ impl Datum {
             reader: &mut R,
             case_vars: &[CaseVar],
             case_start: u64,
+            n_chunks: usize,
         ) -> Result<Option<Vec<Datum>>, Error> {
             let offset = reader.stream_position()?;
-            if offset == case_start {
-                Ok(None)
-            } else {
-                Err(Error::EofInCase {
-                    offset,
+            if n_chunks > 0 {
+                Err(Error::EofInCompressedCase {
                     case_ofs: offset - case_start,
-                    case_len: case_vars.iter().map(CaseVar::bytes).sum(),
+                    n_chunks,
+                    offset,
                 })
+            } else {
+                Ok(None)
             }
         }
 
         let case_start = reader.stream_position()?;
+        let mut n_chunks = 0;
         let mut values = Vec::with_capacity(case_vars.len());
         for var in case_vars {
             match var {
                 CaseVar::Numeric => {
                     let Some(raw) = Self::read_compressed_chunk(reader, codes, endian, bias)?
                     else {
-                        return eof(reader, case_vars, case_start);
+                        return eof(reader, case_vars, case_start, n_chunks);
                     };
+                    n_chunks += 1;
                     values.push(Datum::Number(endian.parse(raw)));
                 }
                 CaseVar::String { width, encoding } => {
@@ -887,12 +953,13 @@ impl Datum {
                             let Some(raw) =
                                 Self::read_compressed_chunk(reader, codes, endian, bias)?
                             else {
-                                return eof(reader, case_vars, case_start);
+                                return eof(reader, case_vars, case_start, n_chunks);
                             };
                             let n_data = data_bytes.min(8);
                             datum.extend_from_slice(&raw[..n_data]);
                             data_bytes -= n_data;
                             padding_bytes -= 8 - n_data;
+                            n_chunks += 1;
                         }
                     }
                     values.push(Datum::String(RawString(datum)));
@@ -963,10 +1030,7 @@ enum ReaderState {
     Start,
     Headers,
     ZlibHeader,
-    ZlibTrailer {
-        ztrailer_offset: u64,
-        ztrailer_len: u64,
-    },
+    ZlibTrailer(ZHeader),
     End,
 }
 
@@ -1058,26 +1122,24 @@ where
                 Some(Ok(record))
             }
             ReaderState::ZlibHeader => {
-                let zheader =
-                    match ZHeader::read(self.0.reader.as_mut().unwrap(), self.0.header.endian) {
-                        Ok(zheader) => zheader,
-                        Err(error) => return Some(Err(error)),
-                    };
-                self.0.state = ReaderState::ZlibTrailer {
-                    ztrailer_offset: zheader.ztrailer_offset,
-                    ztrailer_len: zheader.ztrailer_len,
+                let zheader = match ZHeader::read(
+                    self.0.reader.as_mut().unwrap(),
+                    self.0.header.endian,
+                    &mut self.0.warn,
+                ) {
+                    Ok(zheader) => zheader,
+                    Err(error) => return Some(Err(error)),
                 };
+                self.0.state = ReaderState::ZlibTrailer(zheader.clone());
                 Some(Ok(Record::ZHeader(zheader)))
             }
-            ReaderState::ZlibTrailer {
-                ztrailer_offset,
-                ztrailer_len,
-            } => {
+            ReaderState::ZlibTrailer(ref zheader) => {
                 match ZTrailer::read(
                     self.0.reader.as_mut().unwrap(),
                     self.0.header.endian,
-                    ztrailer_offset,
-                    ztrailer_len,
+                    self.0.header.bias,
+                    zheader,
+                    &mut self.0.warn,
                 ) {
                     Ok(None) => {
                         self.cases();
@@ -3345,12 +3407,31 @@ pub struct ZHeader {
 }
 
 impl ZHeader {
-    fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZHeader, Error> {
+    fn read<R: Read + Seek>(
+        r: &mut R,
+        endian: Endian,
+        warn: &mut dyn FnMut(Warning),
+    ) -> Result<ZHeader, Error> {
         let offset = r.stream_position()?;
         let zheader_offset: u64 = endian.parse(read_bytes(r)?);
         let ztrailer_offset: u64 = endian.parse(read_bytes(r)?);
         let ztrailer_len: u64 = endian.parse(read_bytes(r)?);
 
+        if zheader_offset != offset {
+            return Err(Error::UnexpectedZHeaderOffset {
+                actual: zheader_offset,
+                expected: offset,
+            });
+        }
+
+        if ztrailer_offset < offset {
+            return Err(Error::ImpossibleZTrailerOffset(ztrailer_offset));
+        }
+
+        if ztrailer_len < 24 || ztrailer_len % 24 != 0 {
+            return Err(Error::InvalidZTrailerLength(ztrailer_len));
+        }
+
         Ok(ZHeader {
             offset,
             zheader_offset,
@@ -3411,32 +3492,106 @@ impl ZTrailer {
     fn read<R: Read + Seek>(
         reader: &mut R,
         endian: Endian,
-        ztrailer_ofs: u64,
-        ztrailer_len: u64,
+        bias: f64,
+        zheader: &ZHeader,
+        warn: &mut dyn FnMut(Warning),
     ) -> Result<Option<ZTrailer>, Error> {
         let start_offset = reader.stream_position()?;
-        if reader.seek(SeekFrom::Start(ztrailer_ofs)).is_err() {
+        if reader
+            .seek(SeekFrom::Start(zheader.ztrailer_offset))
+            .is_err()
+        {
             return Ok(None);
         }
         let int_bias = endian.parse(read_bytes(reader)?);
+        if int_bias as f64 != -bias {
+            return Err(Error::WrongZlibTrailerBias {
+                actual: int_bias,
+                expected: -bias,
+            });
+        }
         let zero = endian.parse(read_bytes(reader)?);
+        if zero != 0 {
+            return Err(Error::WrongZlibTrailerZero(zero));
+        }
         let block_size = endian.parse(read_bytes(reader)?);
+        if block_size != 0x3ff000 {
+            return Err(Error::WrongZlibTrailerBlockSize(block_size));
+        }
         let n_blocks: u32 = endian.parse(read_bytes(reader)?);
-        let expected_n_blocks = (ztrailer_len - 24) / 24;
+        let expected_n_blocks = (zheader.ztrailer_len - 24) / 24;
         if n_blocks as u64 != expected_n_blocks {
             return Err(Error::BadZlibTrailerNBlocks {
-                offset: ztrailer_ofs,
+                offset: zheader.ztrailer_offset,
                 n_blocks,
                 expected_n_blocks,
-                ztrailer_len,
+                ztrailer_len: zheader.ztrailer_len,
             });
         }
         let blocks = (0..n_blocks)
             .map(|_| ZBlock::read(reader, endian))
             .collect::<Result<Vec<_>, _>>()?;
+
+        let mut expected_uncmp_ofs = zheader.zheader_offset;
+        let mut expected_cmp_ofs = zheader.zheader_offset + 24;
+        for (index, block) in blocks.iter().enumerate() {
+            if block.uncompressed_ofs != expected_uncmp_ofs {
+                return Err(Error::ZlibTrailerBlockWrongUncmpOfs {
+                    index,
+                    actual: block.uncompressed_ofs,
+                    expected: expected_cmp_ofs,
+                });
+            }
+            if block.compressed_ofs != expected_cmp_ofs {
+                return Err(Error::ZlibTrailerBlockWrongCmpOfs {
+                    index,
+                    actual: block.compressed_ofs,
+                    expected: expected_cmp_ofs,
+                });
+            }
+            if index < blocks.len() - 1 {
+                if block.uncompressed_size != block_size {
+                    warn(Warning::ZlibTrailerBlockWrongSize {
+                        index,
+                        actual: block.uncompressed_size,
+                        expected: block_size,
+                    });
+                }
+            } else {
+                if block.uncompressed_size > block_size {
+                    warn(Warning::ZlibTrailerBlockTooBig {
+                        index,
+                        actual: block.uncompressed_size,
+                        max_expected: block_size,
+                    });
+                }
+            }
+            // http://www.zlib.net/zlib_tech.html says that the maximum
+            // expansion from compression, with worst-case parameters, is 13.5%
+            // plus 11 bytes.  This code checks for an expansion of more than
+            // 14.3% plus 11 bytes.
+            if block.compressed_size > block.uncompressed_size + block.uncompressed_size / 7 + 11 {
+                return Err(Error::ZlibExpansion {
+                    index,
+                    compressed_size: block.compressed_size,
+                    uncompressed_size: block.uncompressed_size,
+                });
+            }
+
+            expected_cmp_ofs += block.compressed_size as u64;
+            expected_uncmp_ofs += block.uncompressed_size as u64;
+        }
+
+        if expected_cmp_ofs != zheader.ztrailer_offset {
+            return Err(Error::ZlibTrailerOffsetInconsistency {
+                descriptors: expected_cmp_ofs,
+                zheader: zheader.ztrailer_offset,
+            });
+        }
+
         reader.seek(SeekFrom::Start(start_offset))?;
         Ok(Some(ZTrailer {
-            offset: ztrailer_ofs,
+            offset: zheader.ztrailer_offset,
             int_bias,
             zero,
             block_size,
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bd5f2635decfadfa48541391ae65caafa0992b7e 100644 (file)
@@ -0,0 +1,31 @@
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │SAV                     │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬────────────────────────╮
+│Label    │PSPP synthetic test file│
+│Variables│                       5│
+╰─────────┴────────────────────────╯
+
+╭─────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│     │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├─────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│num1 │       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+│num2 │       2│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+│str4 │       3│     │Nominal          │Input│    4│Left     │A4          │A4          │              │
+│str8 │       4│     │Nominal          │Input│    8│Left     │A8          │A8          │              │
+│str15│       5│     │Nominal          │Input│   15│Left     │A15         │A15         │              │
+╰─────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+Unexpected end of file at offset 0x1ac, 0 bytes and 2 compression chunks into a compressed case.
+
+╭────┬──────┬────┬────────┬────────────────┬──────────────────────────────╮
+│Case│ num1 │num2│  str4  │      str8      │             str15            │
+├────┼──────┼────┼────────┼────────────────┼──────────────────────────────┤
+│1   │-99.00│ .00│        │abcdefgh        │        0123                  │
+╰────┴──────┴────┴────────┴────────────────┴──────────────────────────────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1b2222eb0005b2d643e7e65afb2fe4f77b032c38 100644 (file)
@@ -0,0 +1,27 @@
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │None                    │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│2│
+╰─────────┴─╯
+
+╭────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│    │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│num1│       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+│num2│       2│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+╰────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+Unexpected end of file at offset 0x12c, 8 bytes into a 16-byte case.
+
+╭────┬────┬────╮
+│Case│num1│num2│
+├────┼────┼────┤
+│1   │1.00│2.00│
+╰────┴────┴────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b1c0844998ae8dd9aae0e7c63460f91c1573bbd9 100644 (file)
@@ -0,0 +1,26 @@
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │None                    │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬─╮
+│Variables│1│
+╰─────────┴─╯
+
+╭─────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│     │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├─────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│str14│       1│     │Nominal          │Input│   14│Left     │A14         │A14         │              │
+╰─────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+I/O error (failed to fill whole buffer)
+
+╭────┬──────────────╮
+│Case│     str14    │
+├────┼──────────────┤
+│1   │one data item │
+╰────┴──────────────╯
index bdb0b0da0717094f2e5446eb073f77c4035f5043..12cfebb0c6cf7e3e716dc77b1613d03d493d279b 100644 (file)
@@ -18,3 +18,9 @@
 │num1                      │       1│                          │                 │Input│    8│Right    │F8.0        │F8.0        │              │
 │Numeric variable 2's label│       2│Numeric variable 2's label│                 │Input│    8│Right    │F8.0        │F8.0        │              │
 ╰──────────────────────────┴────────┴──────────────────────────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭────┬────┬──────────────────────────╮
+│Case│num1│Numeric variable 2's label│
+├────┼────┼──────────────────────────┤
+│1   │1.00│                      2.00│
+╰────┴────┴──────────────────────────╯
index a448646811114847db7108aea7f6c3a74805cd66..264872394679a6b434e16ce71b31e8b024fc8b8c 100644 (file)
@@ -38,3 +38,9 @@
 │str10                           │      20│                                │Nominal          │Input│   11│Left     │A11         │A11         │"abcdefgh"; "01234567"; "0"│
 │25-byte string                  │      21│25-byte string                  │Nominal          │Input│   25│Left     │A25         │A25         │                           │
 ╰────────────────────────────────┴────────┴────────────────────────────────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴───────────────────────────╯
+
+╭────┬────┬────────────────────────────────┬────┬──────────────────────────────┬────┬────┬────┬────┬────┬────────┬────┬─────────────────────────┬────┬─────────────────────────────┬────┬────┬───────────┬─────────┬──────────┬───────────┬─────────────────────────╮
+│Case│num1│Numeric variable 2's label (ùúû)│num3│Another numeric variable label│num5│num6│num7│num8│num9│numàèìñò│str1│String variable 2's label│str3│Another string variable label│str5│str6│    str7   │   str8  │   str9   │   str10   │      25-byte string     │
+├────┼────┼────────────────────────────────┼────┼──────────────────────────────┼────┼────┼────┼────┼────┼────────┼────┼─────────────────────────┼────┼─────────────────────────────┼────┼────┼───────────┼─────────┼──────────┼───────────┼─────────────────────────┤
+│1   │1.00│                            2.00│3.00│                          4.00│5.00│6.00│7.00│8.00│9.00│   10.00│abcd│efgh                     │ijkl│mnop                         │qrst│uvwx│yzABCDEFGHI│JKLMNOPQR│STUVWXYZ01│23456789abc│defghijklmnopqstuvwxyzABC│
+╰────┴────┴────────────────────────────────┴────┴──────────────────────────────┴────┴────┴────┴────┴────┴────────┴────┴─────────────────────────┴────┴─────────────────────────────┴────┴────┴───────────┴─────────┴──────────┴───────────┴─────────────────────────╯
index 119a3389d8046203cf843f8c73a40d156071edae..d701ada126098b14ddb2117d473e4dee119524cc 100644 (file)
@@ -19,3 +19,9 @@
 │num1                      │       1│                          │                 │Input│    8│Right    │F8.0        │F8.0        │              │
 │Numeric variable 2's label│       2│Numeric variable 2's label│                 │Input│    8│Right    │F8.0        │F8.0        │              │
 ╰──────────────────────────┴────────┴──────────────────────────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭────┬────┬──────────────────────────╮
+│Case│num1│Numeric variable 2's label│
+├────┼────┼──────────────────────────┤
+│1   │1.00│                      2.00│
+╰────┴────┴──────────────────────────╯
index 396ece9038e16a32bac5fcb6215f18d111aa1734..41e507a5807121e17265c90396ef80010b25fdec 100644 (file)
 │str8 │       4│     │Nominal          │Input│    8│Left     │A8          │A8          │              │
 │str15│       5│     │Nominal          │Input│   15│Left     │A15         │A15         │              │
 ╰─────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭────┬──────┬──────┬────────┬────────────────┬──────────────────────────────╮
+│Case│ num1 │ num2 │  str4  │      str8      │             str15            │
+├────┼──────┼──────┼────────┼────────────────┼──────────────────────────────┤
+│1   │-99.00│   .00│        │abcdefgh        │        0123                  │
+│2   │   .  │151.00│jklm    │nopqrstu        │vwxyzABC                      │
+│3   │  1.00│  2.00│DEFG    │HIJKLMNO        │        PQRSTUV               │
+╰────┴──────┴──────┴────────┴────────────────┴──────────────────────────────╯
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..99b16acc5a62a94079d00bbc1b1523dbcb526245 100644 (file)
@@ -0,0 +1 @@
+ZLIB header's zlib_offset is 0x0 instead of expected 0x194.
index bbe7020845a9df622033469b503770a62598c94e..7d86604f362051c3e4de78d8253624076366adb3 100644 (file)
@@ -27,7 +27,7 @@ i8 0 *3;
 999; 0;
 
 # ZLIB data header.
-i64 0x194;    # zheader_ofs
+>>i64 0<<;    # zheader_ofs
 i64 0x205;    # ztrailer_ofs
 i64 48;       # ztrailer_len
 
index bbe7020845a9df622033469b503770a62598c94e..287c656423fd16ca8e2ab4e0447de2c0a90cb5c3 100644 (file)
@@ -28,7 +28,7 @@ i8 0 *3;
 
 # ZLIB data header.
 i64 0x194;    # zheader_ofs
-i64 0x205;    # ztrailer_ofs
+>>i64 0<<;    # ztrailer_ofs
 i64 48;       # ztrailer_len
 
 # ZLIB data block.
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d8b17d3569c02c954ff3cdeee33916b2d90fd900 100644 (file)
@@ -0,0 +1 @@
+ZLIB trailer is at offset 0x205 but 0x204 would be expected from block descriptors.
index bbe7020845a9df622033469b503770a62598c94e..06f20d031f7cdbe4e1a8a581c8c7fca4605d0167 100644 (file)
@@ -60,4 +60,4 @@ i64 0;        # ztrailer_zero
 i64 0x194;    # uncompressed_ofs
 i64 0x1ac;    # compressed_ofs
 88;           # uncompressed_size
-89;           # compressed_size
+>>88<<;       # compressed_size
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..df98439368ba64351d9aa3de06a93206e1cd80f9 100644 (file)
@@ -0,0 +1 @@
+ZLIB block descriptor 1 reported compressed data offset 0x12421, when 0x124f1 was expected.
index bbe7020845a9df622033469b503770a62598c94e..bc2627e09d8ca5998ffdd2b4fec3ba33d69c52de 100644 (file)
@@ -59,5 +59,5 @@ i64 0;        # ztrailer_zero
 # ZLIB block descriptor:
 i64 0x194;    # uncompressed_ofs
 i64 0x1ac;    # compressed_ofs
-88;           # uncompressed_size
-89;           # compressed_size
+>>50<<;       # uncompressed_size
+>>100<<;      # compressed_size
index bbe7020845a9df622033469b503770a62598c94e..0b03e4a597901d776d20988370dd761216a68d21 100644 (file)
@@ -29,7 +29,7 @@ i8 0 *3;
 # ZLIB data header.
 i64 0x194;    # zheader_ofs
 i64 0x205;    # ztrailer_ofs
-i64 48;       # ztrailer_len
+>>i64 21<<;   # ztrailer_len
 
 # ZLIB data block.
 #
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a1a839cdf2a6b22d7a796a0832e69e8c58d836dd 100644 (file)
@@ -0,0 +1,33 @@
+ZLIB block descriptor 0 reported block size 0x400000, when at most 0x3ff000 was expected.
+
+╭──────────────────────┬────────────────────────╮
+│       Created        │    01-JAN-2011 20:53:52│
+├──────────────────────┼────────────────────────┤
+│Writer Product        │PSPP synthetic test file│
+├──────────────────────┼────────────────────────┤
+│       Compression    │ZSAV                    │
+│       Number of Cases│Unknown                 │
+╰──────────────────────┴────────────────────────╯
+
+╭─────────┬────────────────────────╮
+│Label    │PSPP synthetic test file│
+│Variables│                       5│
+╰─────────┴────────────────────────╯
+
+╭─────┬────────┬─────┬─────────────────┬─────┬─────┬─────────┬────────────┬────────────┬──────────────╮
+│     │Position│Label│Measurement Level│ Role│Width│Alignment│Print Format│Write Format│Missing Values│
+├─────┼────────┼─────┼─────────────────┼─────┼─────┼─────────┼────────────┼────────────┼──────────────┤
+│num1 │       1│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+│num2 │       2│     │                 │Input│    8│Right    │F8.0        │F8.0        │              │
+│str4 │       3│     │Nominal          │Input│    4│Left     │A4          │A4          │              │
+│str8 │       4│     │Nominal          │Input│    8│Left     │A8          │A8          │              │
+│str15│       5│     │Nominal          │Input│   15│Left     │A15         │A15         │              │
+╰─────┴────────┴─────┴─────────────────┴─────┴─────┴─────────┴────────────┴────────────┴──────────────╯
+
+╭────┬──────┬──────┬────────┬────────────────┬──────────────────────────────╮
+│Case│ num1 │ num2 │  str4  │      str8      │             str15            │
+├────┼──────┼──────┼────────┼────────────────┼──────────────────────────────┤
+│1   │-99.00│   .00│        │abcdefgh        │        0123                  │
+│2   │   .  │151.00│jklm    │nopqrstu        │vwxyzABC                      │
+│3   │  1.00│  2.00│DEFG    │HIJKLMNO        │        PQRSTUV               │
+╰────┴──────┴──────┴────────┴────────────────┴──────────────────────────────╯
index bbe7020845a9df622033469b503770a62598c94e..11b26511648e20be23a4fb2a7d8c28136fca786e 100644 (file)
@@ -59,5 +59,5 @@ i64 0;        # ztrailer_zero
 # ZLIB block descriptor:
 i64 0x194;    # uncompressed_ofs
 i64 0x1ac;    # compressed_ofs
-88;           # uncompressed_size
+>>0x400000<<; # uncompressed_size
 89;           # compressed_size
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4c3ed56a7c36ba0d7f68110446ec66ad7a8c0239 100644 (file)
@@ -0,0 +1 @@
+ZLIB trailer specifies unexpected 4096-byte block size.
index bbe7020845a9df622033469b503770a62598c94e..83ef9b18fbcda28bf02bd9f365f3ef8637a7b5ef 100644 (file)
@@ -53,7 +53,7 @@ hex "90 d0 b0 70 00 0f 3f 23  d7";
 # ZLIB data trailer fixed header:
 i64 -100;     # ztrailer_bias
 i64 0;        # ztrailer_zero
-0x3ff000;     # block_size
+>>0x1000<<;   # block_size
 1;            # n_blocks
 
 # ZLIB block descriptor:
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0f86bbcc44af0083310c2f24fbb758ffceb84d12 100644 (file)
@@ -0,0 +1 @@
+ZLIB block descriptor 0 reported compressed data offset 0x191, when 0x1ac was expected.
index bbe7020845a9df622033469b503770a62598c94e..e575aa6b87b6d30a52ce7b53e95d12ff2fe94ca2 100644 (file)
@@ -58,6 +58,6 @@ i64 0;        # ztrailer_zero
 
 # ZLIB block descriptor:
 i64 0x194;    # uncompressed_ofs
-i64 0x1ac;    # compressed_ofs
+>>i64 0x191<<;# compressed_ofs
 88;           # uncompressed_size
 89;           # compressed_size
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e2cd618f705d0694021f88dbae9d5ccb4320f283 100644 (file)
@@ -0,0 +1 @@
+Block count 2 in ZLIB trailer at offset 0x205 differs from expected block count 1 calculated from trailer length 48.
index bbe7020845a9df622033469b503770a62598c94e..6f5920707c41b77c27dc730b4a5051293d2779d0 100644 (file)
@@ -54,7 +54,7 @@ hex "90 d0 b0 70 00 0f 3f 23  d7";
 i64 -100;     # ztrailer_bias
 i64 0;        # ztrailer_zero
 0x3ff000;     # block_size
-1;            # n_blocks
+>>2<<;        # n_blocks
 
 # ZLIB block descriptor:
 i64 0x194;    # uncompressed_ofs
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0a2af92d87d0a87fb405c4abb05086a29cf29078 100644 (file)
@@ -0,0 +1 @@
+ZLIB block descriptor 0 reported uncompressed data offset 0x177, when 0x1ac was expected.
index bbe7020845a9df622033469b503770a62598c94e..7d21286d2466f6c21d900a215b31899c1f56018d 100644 (file)
@@ -57,7 +57,7 @@ i64 0;        # ztrailer_zero
 1;            # n_blocks
 
 # ZLIB block descriptor:
-i64 0x194;    # uncompressed_ofs
+i64 >>0x177<<;# uncompressed_ofs
 i64 0x1ac;    # compressed_ofs
 88;           # uncompressed_size
 89;           # compressed_size
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dbfa4c1cb043167dc37ab08ae241dc115d884eff 100644 (file)
@@ -0,0 +1 @@
+ZLIB trailer bias 0 is not -100 as expected from file header bias.
index bbe7020845a9df622033469b503770a62598c94e..efd526379c9c231d1bb0641431ed903ef445d2d5 100644 (file)
@@ -51,7 +51,7 @@ hex "5e de 3e be 7e fe ff fe  fe 61 00 81 80 c0 a0 e0";
 hex "90 d0 b0 70 00 0f 3f 23  d7";
 
 # ZLIB data trailer fixed header:
-i64 -100;     # ztrailer_bias
+>>i64 0<<;    # ztrailer_bias
 i64 0;        # ztrailer_zero
 0x3ff000;     # block_size
 1;            # n_blocks
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0b98a9701c54f83aa85101f73df25be64e19e7a7 100644 (file)
@@ -0,0 +1 @@
+Block count 1 in ZLIB trailer at offset 0x205 differs from expected block count 2 calculated from trailer length 72.
index bbe7020845a9df622033469b503770a62598c94e..e81a92a015dccfb3badf2171886b699f2bd24991 100644 (file)
@@ -29,7 +29,7 @@ i8 0 *3;
 # ZLIB data header.
 i64 0x194;    # zheader_ofs
 i64 0x205;    # ztrailer_ofs
-i64 48;       # ztrailer_len
+>>i64 72<<;   # ztrailer_len
 
 # ZLIB data block.
 #
index bbe7020845a9df622033469b503770a62598c94e..fa59e362b413a17f15b8262ae991659c94b2a166 100644 (file)
@@ -52,7 +52,7 @@ hex "90 d0 b0 70 00 0f 3f 23  d7";
 
 # ZLIB data trailer fixed header:
 i64 -100;     # ztrailer_bias
-i64 0;        # ztrailer_zero
+>>i64 100<<;  # ztrailer_zero
 0x3ff000;     # block_size
 1;            # n_blocks