decodedrecord works
[pspp] / rust / src / raw.rs
1 use crate::{
2     dictionary::VarWidth,
3     endian::{Endian, Parse, ToBytes},
4     identifier::{Error as IdError, Identifier},
5 };
6
7 use encoding_rs::{mem::decode_latin1, DecoderResult, Encoding};
8 use flate2::read::ZlibDecoder;
9 use num::Integer;
10 use std::{
11     borrow::Cow,
12     cell::RefCell,
13     cmp::Ordering,
14     collections::{HashMap, VecDeque},
15     fmt::{Debug, Display, Formatter, Result as FmtResult},
16     io::{Error as IoError, Read, Seek, SeekFrom},
17     iter::repeat,
18     mem::take,
19     ops::Range,
20     rc::Rc,
21     str::from_utf8,
22 };
23 use thiserror::Error as ThisError;
24
25 #[derive(ThisError, Debug)]
26 pub enum Error {
27     #[error("Not an SPSS system file")]
28     NotASystemFile,
29
30     #[error("Invalid magic number {0:?}")]
31     BadMagic([u8; 4]),
32
33     #[error("I/O error ({0})")]
34     Io(#[from] IoError),
35
36     #[error("Invalid SAV compression code {0}")]
37     InvalidSavCompression(u32),
38
39     #[error("Invalid ZSAV compression code {0}")]
40     InvalidZsavCompression(u32),
41
42     #[error("Variable record at offset {offset:#x} specifies width {width} not in valid range [-1,255).")]
43     BadVariableWidth { offset: u64, width: i32 },
44
45     #[error("Document record at offset {offset:#x} has document line count ({n}) greater than the maximum number {max}.")]
46     BadDocumentLength { offset: u64, n: usize, max: usize },
47
48     #[error("At offset {offset:#x}, unrecognized record type {rec_type}.")]
49     BadRecordType { offset: u64, rec_type: u32 },
50
51     #[error("In variable record starting at offset {start_offset:#x}, variable label code {code} at offset {code_offset:#x} is not 0 or 1.")]
52     BadVariableLabelCode {
53         start_offset: u64,
54         code_offset: u64,
55         code: u32,
56     },
57
58     #[error(
59         "At offset {offset:#x}, numeric missing value code ({code}) is not -3, -2, 0, 1, 2, or 3."
60     )]
61     BadNumericMissingValueCode { offset: u64, code: i32 },
62
63     #[error("At offset {offset:#x}, string missing value code ({code}) is not 0, 1, 2, or 3.")]
64     BadStringMissingValueCode { offset: u64, code: i32 },
65
66     #[error("At offset {offset:#x}, number of value labels ({n}) is greater than the maximum number {max}.")]
67     BadNumberOfValueLabels { offset: u64, n: u32, max: u32 },
68
69     #[error("At offset {offset:#x}, following value label record, found record type {rec_type} instead of expected type 4 for variable index record")]
70     ExpectedVarIndexRecord { offset: u64, rec_type: u32 },
71
72     #[error("At offset {offset:#x}, number of variables indexes for value labels ({n}) is greater than the maximum number ({max}).")]
73     TooManyVarIndexes { offset: u64, n: u32, max: u32 },
74
75     #[error("At offset {offset:#x}, at least one valid variable index for value labels is required but none were specified.")]
76     NoVarIndexes { offset: u64 },
77
78     #[error("At offset {offset:#x}, the first variable index is for a {var_type} variable but the following variable indexes are for {} variables: {wrong_types:?}", var_type.opposite())]
79     MixedVarTypes {
80         offset: u64,
81         var_type: VarType,
82         wrong_types: Vec<u32>,
83     },
84
85     #[error("At offset {offset:#x}, one or more variable indexes for value labels were not in the valid range [1,{max}]: {invalid:?}")]
86     InvalidVarIndexes {
87         offset: u64,
88         max: usize,
89         invalid: Vec<u32>,
90     },
91
92     #[error("At offset {offset:#x}, record type 7 subtype {subtype} is too large with element size {size} and {count} elements.")]
93     ExtensionRecordTooLarge {
94         offset: u64,
95         subtype: u32,
96         size: u32,
97         count: u32,
98     },
99
100     #[error("Unexpected end of file at offset {offset:#x}, {case_ofs} bytes into a {case_len}-byte case.")]
101     EofInCase {
102         offset: u64,
103         case_ofs: u64,
104         case_len: usize,
105     },
106
107     #[error(
108         "Unexpected end of file at offset {offset:#x}, {case_ofs} bytes into a compressed case."
109     )]
110     EofInCompressedCase { offset: u64, case_ofs: u64 },
111
112     #[error("Data ends at offset {offset:#x}, {case_ofs} bytes into a compressed case.")]
113     PartialCompressedCase { offset: u64, case_ofs: u64 },
114
115     #[error("At {case_ofs} bytes into compressed case starting at offset {offset:#x}, a string was found where a number was expected.")]
116     CompressedNumberExpected { offset: u64, case_ofs: u64 },
117
118     #[error("At {case_ofs} bytes into compressed case starting at offset {offset:#x}, a number was found where a string was expected.")]
119     CompressedStringExpected { offset: u64, case_ofs: u64 },
120
121     #[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}.")]
122     BadZlibTrailerNBlocks {
123         offset: u64,
124         n_blocks: u32,
125         expected_n_blocks: u64,
126         ztrailer_len: u64,
127     },
128
129     #[error("At offset {offset:#x}, {record} has bad size {size} bytes instead of the expected {expected_size}.")]
130     BadRecordSize {
131         offset: u64,
132         record: String,
133         size: u32,
134         expected_size: u32,
135     },
136
137     #[error("At offset {offset:#x}, {record} has bad count {count} instead of the expected {expected_count}.")]
138     BadRecordCount {
139         offset: u64,
140         record: String,
141         count: u32,
142         expected_count: u32,
143     },
144
145     #[error("In long string missing values record starting at offset {record_offset:#x}, value length at offset {offset:#x} is {value_len} instead of the expected 8.")]
146     BadLongMissingValueLength {
147         record_offset: u64,
148         offset: u64,
149         value_len: u32,
150     },
151
152     #[error("The encoding record at offset {offset:#x} contains an encoding name that is not valid UTF-8.")]
153     BadEncodingName { offset: u64 },
154
155     // XXX This is risky because `text` might be arbitarily long.
156     #[error("Text string contains invalid bytes for {encoding} encoding: {text}")]
157     MalformedString { encoding: String, text: String },
158
159     #[error("Invalid variable measurement level value {0}")]
160     InvalidMeasurement(u32),
161
162     #[error("Invalid variable display alignment value {0}")]
163     InvalidAlignment(u32),
164
165     #[error("Invalid attribute name.  {0}")]
166     InvalidAttributeName(IdError),
167
168     #[error("Invalid variable name in attribute record.  {0}")]
169     InvalidAttributeVariableName(IdError),
170
171     #[error("Invalid short name in long variable name record.  {0}")]
172     InvalidShortName(IdError),
173
174     #[error("Invalid name in long variable name record.  {0}")]
175     InvalidLongName(IdError),
176
177     #[error("Invalid variable name in very long string record.  {0}")]
178     InvalidLongStringName(IdError),
179
180     #[error("Invalid variable name in variable set record.  {0}")]
181     InvalidVariableSetName(IdError),
182
183     #[error("Invalid multiple response set name.  {0}")]
184     InvalidMrSetName(IdError),
185
186     #[error("Invalid multiple response set variable name.  {0}")]
187     InvalidMrSetVariableName(IdError),
188
189     #[error("Invalid variable name in long string missing values record.  {0}")]
190     InvalidLongStringMissingValueVariableName(IdError),
191
192     #[error("Invalid variable name in long string value label record.  {0}")]
193     InvalidLongStringValueLabelName(IdError),
194
195     #[error("Details TBD")]
196     TBD,
197 }
198
199 #[derive(Clone, Debug)]
200 pub enum Record {
201     Header(HeaderRecord<RawString>),
202     Variable(VariableRecord<RawString, RawStr<8>>),
203     ValueLabel(ValueLabelRecord<RawStr<8>, RawString>),
204     Document(DocumentRecord<RawDocumentLine>),
205     IntegerInfo(IntegerInfoRecord),
206     FloatInfo(FloatInfoRecord),
207     VarDisplay(VarDisplayRecord),
208     MultipleResponse(MultipleResponseRecord<RawString, RawString>),
209     LongStringValueLabels(LongStringValueLabelRecord<RawString, RawString>),
210     LongStringMissingValues(LongStringMissingValueRecord<RawString, RawStr<8>>),
211     Encoding(EncodingRecord),
212     NumberOfCases(NumberOfCasesRecord),
213     Text(TextRecord),
214     OtherExtension(Extension),
215     EndOfHeaders(u32),
216     ZHeader(ZHeader),
217     ZTrailer(ZTrailer),
218     Cases(Rc<RefCell<Cases>>),
219 }
220
221 pub enum DecodedRecord<'a> {
222     Header(HeaderRecord<Cow<'a, str>>),
223     Variable(VariableRecord<Cow<'a, str>, String>),
224     ValueLabel(ValueLabelRecord<RawStr<8>, Cow<'a, str>>),
225     Document(DocumentRecord<Cow<'a, str>>),
226     IntegerInfo(IntegerInfoRecord),
227     FloatInfo(FloatInfoRecord),
228     VarDisplay(VarDisplayRecord),
229     MultipleResponse(MultipleResponseRecord<Identifier, Cow<'a, str>>),
230     LongStringValueLabels(LongStringValueLabelRecord<Identifier, Cow<'a, str>>),
231     LongStringMissingValues(LongStringMissingValueRecord<Identifier, String>),
232     Encoding(EncodingRecord),
233     NumberOfCases(NumberOfCasesRecord),
234     VariableSets(VariableSetRecord),
235     ProductInfo(ProductInfoRecord),
236     LongNames(LongNamesRecord),
237     VeryLongStrings(VeryLongStringsRecord),
238     FileAttributes(FileAttributeRecord),
239     VariableAttributes(VariableAttributeRecord),
240     OtherExtension(Extension),
241     EndOfHeaders(u32),
242     ZHeader(ZHeader),
243     ZTrailer(ZTrailer),
244 }
245
246 impl Record {
247     fn read<R>(
248         reader: &mut R,
249         endian: Endian,
250         var_types: &[VarType],
251         warn: &Box<dyn Fn(Error)>,
252     ) -> Result<Option<Record>, Error>
253     where
254         R: Read + Seek,
255     {
256         let rec_type: u32 = endian.parse(read_bytes(reader)?);
257         match rec_type {
258             2 => Ok(Some(VariableRecord::read(reader, endian)?)),
259             3 => Ok(ValueLabelRecord::read(reader, endian, var_types, warn)?),
260             6 => Ok(Some(DocumentRecord::read(reader, endian)?)),
261             7 => Extension::read(reader, endian, var_types.len(), warn),
262             999 => Ok(Some(Record::EndOfHeaders(
263                 endian.parse(read_bytes(reader)?),
264             ))),
265             _ => Err(Error::BadRecordType {
266                 offset: reader.stream_position()?,
267                 rec_type,
268             }),
269         }
270     }
271
272     fn decode<'a>(&'a self, decoder: &Decoder) -> Result<DecodedRecord<'a>, Error> {
273         Ok(match self {
274             Record::Header(record) => record.decode(decoder),
275             Record::Variable(record) => record.decode(decoder),
276             Record::ValueLabel(record) => DecodedRecord::ValueLabel(record.decode(decoder)),
277             Record::Document(record) => record.decode(decoder),
278             Record::IntegerInfo(record) => DecodedRecord::IntegerInfo(record.clone()),
279             Record::FloatInfo(record) => DecodedRecord::FloatInfo(record.clone()),
280             Record::VarDisplay(record) => DecodedRecord::VarDisplay(record.clone()),
281             Record::MultipleResponse(record) => record.decode(decoder),
282             Record::LongStringValueLabels(record) => {
283                 DecodedRecord::LongStringValueLabels(record.decode(decoder)?)
284             }
285             Record::LongStringMissingValues(record) => {
286                 DecodedRecord::LongStringMissingValues(record.decode(decoder))
287             }
288             Record::Encoding(record) => DecodedRecord::Encoding(record.clone()),
289             Record::NumberOfCases(record) => DecodedRecord::NumberOfCases(record.clone()),
290             Record::Text(record) => record.decode(decoder)?,
291             Record::OtherExtension(record) => DecodedRecord::OtherExtension(record.clone()),
292             Record::EndOfHeaders(record) => DecodedRecord::EndOfHeaders(record.clone()),
293             Record::ZHeader(record) => DecodedRecord::ZHeader(record.clone()),
294             Record::ZTrailer(record) => DecodedRecord::ZTrailer(record.clone()),
295             Record::Cases(_) => todo!(),
296         })
297     }
298 }
299
300 // If `s` is valid UTF-8, returns it decoded as UTF-8, otherwise returns it
301 // decoded as Latin-1 (actually bytes interpreted as Unicode code points).
302 fn default_decode(s: &[u8]) -> Cow<str> {
303     from_utf8(s).map_or_else(|_| decode_latin1(s), Cow::from)
304 }
305
306 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
307 pub enum Compression {
308     Simple,
309     ZLib,
310 }
311
312 trait Header {
313     fn offsets(&self) -> Range<u64>;
314 }
315
316 #[derive(Clone)]
317 pub struct HeaderRecord<S>
318 where
319     S: Debug,
320 {
321     /// Offset in file.
322     pub offsets: Range<u64>,
323
324     /// Magic number.
325     pub magic: Magic,
326
327     /// Eye-catcher string, product name, in the file's encoding.  Padded
328     /// on the right with spaces.
329     pub eye_catcher: S,
330
331     /// Layout code, normally either 2 or 3.
332     pub layout_code: u32,
333
334     /// Number of variable positions, or `None` if the value in the file is
335     /// questionably trustworthy.
336     pub nominal_case_size: Option<u32>,
337
338     /// Compression type, if any,
339     pub compression: Option<Compression>,
340
341     /// 1-based variable index of the weight variable, or `None` if the file is
342     /// unweighted.
343     pub weight_index: Option<u32>,
344
345     /// Claimed number of cases, if known.
346     pub n_cases: Option<u32>,
347
348     /// Compression bias, usually 100.0.
349     pub bias: f64,
350
351     /// `dd mmm yy` in the file's encoding.
352     pub creation_date: S,
353
354     /// `HH:MM:SS` in the file's encoding.
355     pub creation_time: S,
356
357     /// File label, in the file's encoding.  Padded on the right with spaces.
358     pub file_label: S,
359
360     /// Endianness of the data in the file header.
361     pub endian: Endian,
362 }
363
364 impl<S> HeaderRecord<S>
365 where
366     S: Debug,
367 {
368     fn debug_field<T>(&self, f: &mut Formatter, name: &str, value: T) -> FmtResult
369     where
370         T: Debug,
371     {
372         writeln!(f, "{name:>17}: {:?}", value)
373     }
374 }
375
376 impl<S> Debug for HeaderRecord<S>
377 where
378     S: Debug,
379 {
380     fn fmt(&self, f: &mut Formatter) -> FmtResult {
381         writeln!(f, "File header record:")?;
382         self.debug_field(f, "Magic", self.magic)?;
383         self.debug_field(f, "Product name", &self.eye_catcher)?;
384         self.debug_field(f, "Layout code", self.layout_code)?;
385         self.debug_field(f, "Nominal case size", self.nominal_case_size)?;
386         self.debug_field(f, "Compression", self.compression)?;
387         self.debug_field(f, "Weight index", self.weight_index)?;
388         self.debug_field(f, "Number of cases", self.n_cases)?;
389         self.debug_field(f, "Compression bias", self.bias)?;
390         self.debug_field(f, "Creation date", &self.creation_date)?;
391         self.debug_field(f, "Creation time", &self.creation_time)?;
392         self.debug_field(f, "File label", &self.file_label)?;
393         self.debug_field(f, "Endianness", self.endian)
394     }
395 }
396
397 impl HeaderRecord<RawString> {
398     fn read<R: Read + Seek>(r: &mut R) -> Result<Self, Error> {
399         let start = r.stream_position()?;
400
401         let magic: [u8; 4] = read_bytes(r)?;
402         let magic: Magic = magic.try_into().map_err(|_| Error::NotASystemFile)?;
403
404         let eye_catcher = RawString(read_vec(r, 60)?);
405         let layout_code: [u8; 4] = read_bytes(r)?;
406         let endian = Endian::identify_u32(2, layout_code)
407             .or_else(|| Endian::identify_u32(2, layout_code))
408             .ok_or_else(|| Error::NotASystemFile)?;
409         let layout_code = endian.parse(layout_code);
410
411         let nominal_case_size: u32 = endian.parse(read_bytes(r)?);
412         let nominal_case_size =
413             (nominal_case_size <= i32::MAX as u32 / 16).then_some(nominal_case_size);
414
415         let compression_code: u32 = endian.parse(read_bytes(r)?);
416         let compression = match (magic, compression_code) {
417             (Magic::Zsav, 2) => Some(Compression::ZLib),
418             (Magic::Zsav, code) => return Err(Error::InvalidZsavCompression(code)),
419             (_, 0) => None,
420             (_, 1) => Some(Compression::Simple),
421             (_, code) => return Err(Error::InvalidSavCompression(code)),
422         };
423
424         let weight_index: u32 = endian.parse(read_bytes(r)?);
425         let weight_index = (weight_index > 0).then_some(weight_index);
426
427         let n_cases: u32 = endian.parse(read_bytes(r)?);
428         let n_cases = (n_cases < i32::MAX as u32 / 2).then_some(n_cases);
429
430         let bias: f64 = endian.parse(read_bytes(r)?);
431
432         let creation_date = RawString(read_vec(r, 9)?);
433         let creation_time = RawString(read_vec(r, 8)?);
434         let file_label = RawString(read_vec(r, 64)?);
435         let _: [u8; 3] = read_bytes(r)?;
436
437         Ok(HeaderRecord {
438             offsets: start..r.stream_position()?,
439             magic,
440             layout_code,
441             nominal_case_size,
442             compression,
443             weight_index,
444             n_cases,
445             bias,
446             creation_date,
447             creation_time,
448             eye_catcher,
449             file_label,
450             endian,
451         })
452     }
453
454     pub fn decode<'a>(&'a self, decoder: &Decoder) -> DecodedRecord<'a> {
455         let eye_catcher = decoder.decode(&self.eye_catcher);
456         let file_label = decoder.decode(&self.file_label);
457         let creation_date = decoder.decode(&self.creation_date);
458         let creation_time = decoder.decode(&self.creation_time);
459         DecodedRecord::Header(HeaderRecord {
460             eye_catcher,
461             weight_index: self.weight_index,
462             n_cases: self.n_cases,
463             file_label,
464             offsets: self.offsets.clone(),
465             magic: self.magic,
466             layout_code: self.layout_code,
467             nominal_case_size: self.nominal_case_size,
468             compression: self.compression,
469             bias: self.bias,
470             creation_date,
471             creation_time,
472             endian: self.endian,
473         })
474     }
475 }
476
477 pub struct Decoder {
478     pub encoding: &'static Encoding,
479     pub warn: Box<dyn Fn(Error)>,
480 }
481
482 impl Decoder {
483     fn warn(&self, error: Error) {
484         (self.warn)(error)
485     }
486     fn decode_slice<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
487         let (output, malformed) = self.encoding.decode_without_bom_handling(input);
488         if malformed {
489             self.warn(Error::MalformedString {
490                 encoding: self.encoding.name().into(),
491                 text: output.clone().into(),
492             });
493         }
494         output
495     }
496
497     fn decode<'a>(&self, input: &'a RawString) -> Cow<'a, str> {
498         self.decode_slice(input.0.as_slice())
499     }
500
501     /// Returns `input` decoded from `self.encoding` into UTF-8 such that
502     /// re-encoding the result back into `self.encoding` will have exactly the
503     /// same length in bytes.
504     ///
505     /// XXX warn about errors?
506     pub fn decode_exact_length<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
507         if let (s, false) = self.encoding.decode_without_bom_handling(input) {
508             // This is the common case.  Usually there will be no errors.
509             s
510         } else {
511             // Unusual case.  Don't bother to optimize it much.
512             let mut decoder = self.encoding.new_decoder_without_bom_handling();
513             let mut output = String::with_capacity(
514                 decoder
515                     .max_utf8_buffer_length_without_replacement(input.len())
516                     .unwrap(),
517             );
518             let mut rest = input;
519             while !rest.is_empty() {
520                 match decoder.decode_to_string_without_replacement(rest, &mut output, true) {
521                     (DecoderResult::InputEmpty, _) => break,
522                     (DecoderResult::OutputFull, _) => unreachable!(),
523                     (DecoderResult::Malformed(a, b), consumed) => {
524                         let skipped = a as usize + b as usize;
525                         output.extend(repeat('?').take(skipped));
526                         rest = &rest[consumed..];
527                     }
528                 }
529             }
530             assert_eq!(self.encoding.encode(&output).0.len(), input.len());
531             output.into()
532         }
533     }
534
535     pub fn decode_identifier(&self, input: &RawString) -> Result<Identifier, IdError> {
536         self.new_identifier(&self.decode(input))
537     }
538
539     pub fn new_identifier(&self, name: &str) -> Result<Identifier, IdError> {
540         Identifier::new(name, self.encoding)
541     }
542 }
543
544 impl<S> Header for HeaderRecord<S>
545 where
546     S: Debug,
547 {
548     fn offsets(&self) -> Range<u64> {
549         self.offsets.clone()
550     }
551 }
552
553 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
554 pub enum Magic {
555     /// Regular system file.
556     Sav,
557
558     /// System file with Zlib-compressed data.
559     Zsav,
560
561     /// EBCDIC-encoded system file.
562     Ebcdic,
563 }
564
565 impl Magic {
566     /// Magic number for a regular system file.
567     pub const SAV: [u8; 4] = *b"$FL2";
568
569     /// Magic number for a system file that contains zlib-compressed data.
570     pub const ZSAV: [u8; 4] = *b"$FL3";
571
572     /// Magic number for an EBCDIC-encoded system file.  This is `$FL2` encoded
573     /// in EBCDIC.
574     pub const EBCDIC: [u8; 4] = [0x5b, 0xc6, 0xd3, 0xf2];
575 }
576
577 impl Debug for Magic {
578     fn fmt(&self, f: &mut Formatter) -> FmtResult {
579         let s = match *self {
580             Magic::Sav => "$FL2",
581             Magic::Zsav => "$FL3",
582             Magic::Ebcdic => "($FL2 in EBCDIC)",
583         };
584         write!(f, "{s}")
585     }
586 }
587
588 impl TryFrom<[u8; 4]> for Magic {
589     type Error = Error;
590
591     fn try_from(value: [u8; 4]) -> Result<Self, Self::Error> {
592         match value {
593             Magic::SAV => Ok(Magic::Sav),
594             Magic::ZSAV => Ok(Magic::Zsav),
595             Magic::EBCDIC => Ok(Magic::Ebcdic),
596             _ => Err(Error::BadMagic(value)),
597         }
598     }
599 }
600
601 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
602 pub enum VarType {
603     Numeric,
604     String,
605 }
606
607 impl VarType {
608     pub fn from_width(width: VarWidth) -> VarType {
609         match width {
610             VarWidth::Numeric => Self::Numeric,
611             VarWidth::String(_) => Self::String,
612         }
613     }
614
615     pub fn opposite(self) -> VarType {
616         match self {
617             Self::Numeric => Self::String,
618             Self::String => Self::Numeric,
619         }
620     }
621 }
622
623 impl Display for VarType {
624     fn fmt(&self, f: &mut Formatter) -> FmtResult {
625         match self {
626             VarType::Numeric => write!(f, "numeric"),
627             VarType::String => write!(f, "string"),
628         }
629     }
630 }
631
632 #[derive(Copy, Clone)]
633 pub enum Value<S>
634 where
635     S: Debug,
636 {
637     Number(Option<f64>),
638     String(S),
639 }
640
641 type RawValue = Value<RawStr<8>>;
642
643 impl<S> Debug for Value<S>
644 where
645     S: Debug,
646 {
647     fn fmt(&self, f: &mut Formatter) -> FmtResult {
648         match self {
649             Value::Number(Some(number)) => write!(f, "{number:?}"),
650             Value::Number(None) => write!(f, "SYSMIS"),
651             Value::String(s) => write!(f, "{:?}", s),
652         }
653     }
654 }
655
656 impl RawValue {
657     fn read<R: Read>(r: &mut R, var_type: VarType, endian: Endian) -> Result<Self, IoError> {
658         Ok(Self::from_raw(
659             &UntypedValue(read_bytes(r)?),
660             var_type,
661             endian,
662         ))
663     }
664
665     pub fn from_raw(raw: &UntypedValue, var_type: VarType, endian: Endian) -> Self {
666         match var_type {
667             VarType::String => Value::String(RawStr(raw.0)),
668             VarType::Numeric => {
669                 let number: f64 = endian.parse(raw.0);
670                 Value::Number((number != -f64::MAX).then_some(number))
671             }
672         }
673     }
674
675     fn read_case<R: Read + Seek>(
676         reader: &mut R,
677         var_types: &[VarType],
678         endian: Endian,
679     ) -> Result<Option<Vec<Self>>, Error> {
680         let case_start = reader.stream_position()?;
681         let mut values = Vec::with_capacity(var_types.len());
682         for (i, &var_type) in var_types.iter().enumerate() {
683             let Some(raw) = try_read_bytes(reader)? else {
684                 if i == 0 {
685                     return Ok(None);
686                 } else {
687                     let offset = reader.stream_position()?;
688                     return Err(Error::EofInCase {
689                         offset,
690                         case_ofs: offset - case_start,
691                         case_len: var_types.len() * 8,
692                     });
693                 }
694             };
695             values.push(Value::from_raw(&UntypedValue(raw), var_type, endian));
696         }
697         Ok(Some(values))
698     }
699
700     fn read_compressed_case<R: Read + Seek>(
701         reader: &mut R,
702         var_types: &[VarType],
703         codes: &mut VecDeque<u8>,
704         endian: Endian,
705         bias: f64,
706     ) -> Result<Option<Vec<Self>>, Error> {
707         let case_start = reader.stream_position()?;
708         let mut values = Vec::with_capacity(var_types.len());
709         for (i, &var_type) in var_types.iter().enumerate() {
710             let value = loop {
711                 let Some(code) = codes.pop_front() else {
712                     let Some(new_codes): Option<[u8; 8]> = try_read_bytes(reader)? else {
713                         if i == 0 {
714                             return Ok(None);
715                         } else {
716                             let offset = reader.stream_position()?;
717                             return Err(Error::EofInCompressedCase {
718                                 offset,
719                                 case_ofs: offset - case_start,
720                             });
721                         }
722                     };
723                     codes.extend(new_codes.into_iter());
724                     continue;
725                 };
726                 match code {
727                     0 => (),
728                     1..=251 => match var_type {
729                         VarType::Numeric => break Self::Number(Some(code as f64 - bias)),
730                         VarType::String => {
731                             break Self::String(RawStr(endian.to_bytes(code as f64 - bias)))
732                         }
733                     },
734                     252 => {
735                         if i == 0 {
736                             return Ok(None);
737                         } else {
738                             let offset = reader.stream_position()?;
739                             return Err(Error::PartialCompressedCase {
740                                 offset,
741                                 case_ofs: offset - case_start,
742                             });
743                         }
744                     }
745                     253 => {
746                         break Self::from_raw(&UntypedValue(read_bytes(reader)?), var_type, endian)
747                     }
748                     254 => match var_type {
749                         VarType::String => break Self::String(RawStr(*b"        ")), // XXX EBCDIC
750                         VarType::Numeric => {
751                             return Err(Error::CompressedStringExpected {
752                                 offset: case_start,
753                                 case_ofs: reader.stream_position()? - case_start,
754                             })
755                         }
756                     },
757                     255 => match var_type {
758                         VarType::Numeric => break Self::Number(None),
759                         VarType::String => {
760                             return Err(Error::CompressedNumberExpected {
761                                 offset: case_start,
762                                 case_ofs: reader.stream_position()? - case_start,
763                             })
764                         }
765                     },
766                 }
767             };
768             values.push(value);
769         }
770         Ok(Some(values))
771     }
772
773     fn decode(&self, decoder: &Decoder) -> Value<String> {
774         match self {
775             Self::Number(x) => Value::Number(*x),
776             Self::String(s) => Value::String(decoder.decode_exact_length(&s.0).into()),
777         }
778     }
779 }
780
781 struct ZlibDecodeMultiple<R>
782 where
783     R: Read + Seek,
784 {
785     reader: Option<ZlibDecoder<R>>,
786 }
787
788 impl<R> ZlibDecodeMultiple<R>
789 where
790     R: Read + Seek,
791 {
792     fn new(reader: R) -> ZlibDecodeMultiple<R> {
793         ZlibDecodeMultiple {
794             reader: Some(ZlibDecoder::new(reader)),
795         }
796     }
797 }
798
799 impl<R> Read for ZlibDecodeMultiple<R>
800 where
801     R: Read + Seek,
802 {
803     fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
804         loop {
805             match self.reader.as_mut().unwrap().read(buf)? {
806                 0 => {
807                     let inner = self.reader.take().unwrap().into_inner();
808                     self.reader = Some(ZlibDecoder::new(inner));
809                 }
810                 n => return Ok(n),
811             };
812         }
813     }
814 }
815
816 impl<R> Seek for ZlibDecodeMultiple<R>
817 where
818     R: Read + Seek,
819 {
820     fn seek(&mut self, pos: SeekFrom) -> Result<u64, IoError> {
821         self.reader.as_mut().unwrap().get_mut().seek(pos)
822     }
823 }
824
825 enum ReaderState {
826     Start,
827     Headers,
828     ZlibHeader,
829     ZlibTrailer {
830         ztrailer_offset: u64,
831         ztrailer_len: u64,
832     },
833     Cases,
834     End,
835 }
836
837 pub struct Reader<R>
838 where
839     R: Read + Seek + 'static,
840 {
841     reader: Option<R>,
842     warn: Box<dyn Fn(Error)>,
843
844     header: HeaderRecord<RawString>,
845     var_types: Vec<VarType>,
846
847     state: ReaderState,
848 }
849
850 impl<R> Reader<R>
851 where
852     R: Read + Seek + 'static,
853 {
854     pub fn new<F>(mut reader: R, warn: F) -> Result<Self, Error>
855     where
856         F: Fn(Error) + 'static,
857     {
858         let header = HeaderRecord::read(&mut reader)?;
859         Ok(Self {
860             reader: Some(reader),
861             warn: Box::new(warn),
862             header,
863             var_types: Vec::new(),
864             state: ReaderState::Start,
865         })
866     }
867     fn cases(&mut self) -> Cases {
868         self.state = ReaderState::End;
869         Cases::new(
870             self.reader.take().unwrap(),
871             take(&mut self.var_types),
872             &self.header,
873         )
874     }
875 }
876
877 impl<R> Iterator for Reader<R>
878 where
879     R: Read + Seek + 'static,
880 {
881     type Item = Result<Record, Error>;
882
883     fn next(&mut self) -> Option<Self::Item> {
884         match self.state {
885             ReaderState::Start => {
886                 self.state = ReaderState::Headers;
887                 Some(Ok(Record::Header(self.header.clone())))
888             }
889             ReaderState::Headers => {
890                 let record = loop {
891                     match Record::read(
892                         self.reader.as_mut().unwrap(),
893                         self.header.endian,
894                         self.var_types.as_slice(),
895                         &self.warn,
896                     ) {
897                         Ok(Some(record)) => break record,
898                         Ok(None) => (),
899                         Err(error) => return Some(Err(error)),
900                     }
901                 };
902                 match record {
903                     Record::Variable(VariableRecord { width, .. }) => {
904                         self.var_types.push(if width == 0 {
905                             VarType::Numeric
906                         } else {
907                             VarType::String
908                         });
909                     }
910                     Record::EndOfHeaders(_) => {
911                         self.state = if let Some(Compression::ZLib) = self.header.compression {
912                             ReaderState::ZlibHeader
913                         } else {
914                             ReaderState::Cases
915                         };
916                     }
917                     _ => (),
918                 };
919                 Some(Ok(record))
920             }
921             ReaderState::ZlibHeader => {
922                 let zheader = match ZHeader::read(self.reader.as_mut().unwrap(), self.header.endian)
923                 {
924                     Ok(zheader) => zheader,
925                     Err(error) => return Some(Err(error)),
926                 };
927                 self.state = ReaderState::ZlibTrailer {
928                     ztrailer_offset: zheader.ztrailer_offset,
929                     ztrailer_len: zheader.ztrailer_len,
930                 };
931                 Some(Ok(Record::ZHeader(zheader)))
932             }
933             ReaderState::ZlibTrailer {
934                 ztrailer_offset,
935                 ztrailer_len,
936             } => {
937                 match ZTrailer::read(
938                     self.reader.as_mut().unwrap(),
939                     self.header.endian,
940                     ztrailer_offset,
941                     ztrailer_len,
942                 ) {
943                     Ok(None) => Some(Ok(Record::Cases(Rc::new(RefCell::new(self.cases()))))),
944                     Ok(Some(ztrailer)) => Some(Ok(Record::ZTrailer(ztrailer))),
945                     Err(error) => Some(Err(error)),
946                 }
947             }
948             ReaderState::Cases => Some(Ok(Record::Cases(Rc::new(RefCell::new(self.cases()))))),
949             ReaderState::End => None,
950         }
951     }
952 }
953
954 trait ReadSeek: Read + Seek {}
955 impl<T> ReadSeek for T where T: Read + Seek {}
956
957 pub struct Cases {
958     reader: Box<dyn ReadSeek>,
959     var_types: Vec<VarType>,
960     compression: Option<Compression>,
961     bias: f64,
962     endian: Endian,
963     codes: VecDeque<u8>,
964     eof: bool,
965 }
966
967 impl Debug for Cases {
968     fn fmt(&self, f: &mut Formatter) -> FmtResult {
969         write!(f, "Cases")
970     }
971 }
972
973 impl Cases {
974     fn new<R>(reader: R, var_types: Vec<VarType>, header: &HeaderRecord<RawString>) -> Self
975     where
976         R: Read + Seek + 'static,
977     {
978         Self {
979             reader: if header.compression == Some(Compression::ZLib) {
980                 Box::new(ZlibDecodeMultiple::new(reader))
981             } else {
982                 Box::new(reader)
983             },
984             var_types,
985             compression: header.compression,
986             bias: header.bias,
987             endian: header.endian,
988             codes: VecDeque::with_capacity(8),
989             eof: false,
990         }
991     }
992 }
993
994 impl Iterator for Cases {
995     type Item = Result<Vec<RawValue>, Error>;
996
997     fn next(&mut self) -> Option<Self::Item> {
998         if self.eof {
999             return None;
1000         }
1001
1002         let retval = if self.compression.is_some() {
1003             Value::read_compressed_case(
1004                 &mut self.reader,
1005                 &self.var_types,
1006                 &mut self.codes,
1007                 self.endian,
1008                 self.bias,
1009             )
1010             .transpose()
1011         } else {
1012             Value::read_case(&mut self.reader, &self.var_types, self.endian).transpose()
1013         };
1014         self.eof = matches!(retval, None | Some(Err(_)));
1015         retval
1016     }
1017 }
1018
1019 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
1020 pub struct Spec(pub u32);
1021
1022 impl Debug for Spec {
1023     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1024         let type_ = format_name(self.0 >> 16);
1025         let w = (self.0 >> 8) & 0xff;
1026         let d = self.0 & 0xff;
1027         write!(f, "{:06x} ({type_}{w}.{d})", self.0)
1028     }
1029 }
1030
1031 fn format_name(type_: u32) -> Cow<'static, str> {
1032     match type_ {
1033         1 => "A",
1034         2 => "AHEX",
1035         3 => "COMMA",
1036         4 => "DOLLAR",
1037         5 => "F",
1038         6 => "IB",
1039         7 => "PIBHEX",
1040         8 => "P",
1041         9 => "PIB",
1042         10 => "PK",
1043         11 => "RB",
1044         12 => "RBHEX",
1045         15 => "Z",
1046         16 => "N",
1047         17 => "E",
1048         20 => "DATE",
1049         21 => "TIME",
1050         22 => "DATETIME",
1051         23 => "ADATE",
1052         24 => "JDATE",
1053         25 => "DTIME",
1054         26 => "WKDAY",
1055         27 => "MONTH",
1056         28 => "MOYR",
1057         29 => "QYR",
1058         30 => "WKYR",
1059         31 => "PCT",
1060         32 => "DOT",
1061         33 => "CCA",
1062         34 => "CCB",
1063         35 => "CCC",
1064         36 => "CCD",
1065         37 => "CCE",
1066         38 => "EDATE",
1067         39 => "SDATE",
1068         40 => "MTIME",
1069         41 => "YMDHMS",
1070         _ => return format!("<unknown format {type_}>").into(),
1071     }
1072     .into()
1073 }
1074
1075 #[derive(Clone)]
1076 pub struct MissingValues<S = String>
1077 where
1078     S: Debug,
1079 {
1080     /// Individual missing values, up to 3 of them.
1081     pub values: Vec<Value<S>>,
1082
1083     /// Optional range of missing values.
1084     pub range: Option<(Value<S>, Value<S>)>,
1085 }
1086
1087 impl<S> Debug for MissingValues<S>
1088 where
1089     S: Debug,
1090 {
1091     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1092         for (i, value) in self.values.iter().enumerate() {
1093             if i > 0 {
1094                 write!(f, ", ")?;
1095             }
1096             write!(f, "{value:?}")?;
1097         }
1098
1099         if let Some((low, high)) = &self.range {
1100             if !self.values.is_empty() {
1101                 write!(f, ", ")?;
1102             }
1103             write!(f, "{low:?} THRU {high:?}")?;
1104         }
1105
1106         if self.is_empty() {
1107             write!(f, "none")?;
1108         }
1109
1110         Ok(())
1111     }
1112 }
1113
1114 impl<S> MissingValues<S>
1115 where
1116     S: Debug,
1117 {
1118     fn is_empty(&self) -> bool {
1119         self.values.is_empty() && self.range.is_none()
1120     }
1121 }
1122
1123 impl<S> Default for MissingValues<S>
1124 where
1125     S: Debug,
1126 {
1127     fn default() -> Self {
1128         Self {
1129             values: Vec::new(),
1130             range: None,
1131         }
1132     }
1133 }
1134
1135 impl MissingValues<RawStr<8>> {
1136     fn read<R: Read + Seek>(
1137         r: &mut R,
1138         offset: u64,
1139         width: i32,
1140         code: i32,
1141         endian: Endian,
1142     ) -> Result<Self, Error> {
1143         let (n_values, has_range) = match (width, code) {
1144             (_, 0..=3) => (code, false),
1145             (0, -2) => (0, true),
1146             (0, -3) => (1, true),
1147             (0, _) => return Err(Error::BadNumericMissingValueCode { offset, code }),
1148             (_, _) => return Err(Error::BadStringMissingValueCode { offset, code }),
1149         };
1150
1151         let var_type = if width == 0 {
1152             VarType::Numeric
1153         } else {
1154             VarType::String
1155         };
1156
1157         let mut values = Vec::new();
1158         for _ in 0..n_values {
1159             values.push(RawValue::read(r, var_type, endian)?);
1160         }
1161         let range = if has_range {
1162             let low = RawValue::read(r, var_type, endian)?;
1163             let high = RawValue::read(r, var_type, endian)?;
1164             Some((low, high))
1165         } else {
1166             None
1167         };
1168         Ok(Self { values, range })
1169     }
1170     fn decode<'a>(&'a self, decoder: &Decoder) -> MissingValues<String> {
1171         MissingValues {
1172             values: self
1173                 .values
1174                 .iter()
1175                 .map(|value| value.decode(decoder))
1176                 .collect(),
1177             range: self
1178                 .range
1179                 .as_ref()
1180                 .map(|(low, high)| (low.decode(decoder), high.decode(decoder))),
1181         }
1182     }
1183 }
1184
1185 #[derive(Clone)]
1186 pub struct VariableRecord<S, V>
1187 where
1188     S: Debug,
1189     V: Debug,
1190 {
1191     /// Range of offsets in file.
1192     pub offsets: Range<u64>,
1193
1194     /// Variable width, in the range -1..=255.
1195     pub width: i32,
1196
1197     /// Variable name, padded on the right with spaces.
1198     pub name: S,
1199
1200     /// Print format.
1201     pub print_format: Spec,
1202
1203     /// Write format.
1204     pub write_format: Spec,
1205
1206     /// Missing values.
1207     pub missing_values: MissingValues<V>,
1208
1209     /// Optional variable label.
1210     pub label: Option<S>,
1211 }
1212
1213 impl<S, V> Debug for VariableRecord<S, V>
1214 where
1215     S: Debug,
1216     V: Debug,
1217 {
1218     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1219         writeln!(
1220             f,
1221             "Width: {} ({})",
1222             self.width,
1223             match self.width.cmp(&0) {
1224                 Ordering::Greater => "string",
1225                 Ordering::Equal => "numeric",
1226                 Ordering::Less => "long string continuation record",
1227             }
1228         )?;
1229         writeln!(f, "Print format: {:?}", self.print_format)?;
1230         writeln!(f, "Write format: {:?}", self.write_format)?;
1231         writeln!(f, "Name: {:?}", &self.name)?;
1232         writeln!(f, "Variable label: {:?}", self.label)?;
1233         writeln!(f, "Missing values: {:?}", self.missing_values)
1234     }
1235 }
1236
1237 impl VariableRecord<RawString, RawStr<8>> {
1238     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1239         let start_offset = r.stream_position()?;
1240         let width: i32 = endian.parse(read_bytes(r)?);
1241         let code_offset = r.stream_position()?;
1242         let has_variable_label: u32 = endian.parse(read_bytes(r)?);
1243         let missing_value_code: i32 = endian.parse(read_bytes(r)?);
1244         let print_format = Spec(endian.parse(read_bytes(r)?));
1245         let write_format = Spec(endian.parse(read_bytes(r)?));
1246         let name = RawString(read_vec(r, 8)?);
1247
1248         let label = match has_variable_label {
1249             0 => None,
1250             1 => {
1251                 let len: u32 = endian.parse(read_bytes(r)?);
1252                 let read_len = len.min(65535) as usize;
1253                 let label = RawString(read_vec(r, read_len)?);
1254
1255                 let padding_bytes = Integer::next_multiple_of(&len, &4) - len;
1256                 let _ = read_vec(r, padding_bytes as usize)?;
1257
1258                 Some(label)
1259             }
1260             _ => {
1261                 return Err(Error::BadVariableLabelCode {
1262                     start_offset,
1263                     code_offset,
1264                     code: has_variable_label,
1265                 })
1266             }
1267         };
1268
1269         let missing_values =
1270             MissingValues::read(r, start_offset, width, missing_value_code, endian)?;
1271
1272         let end_offset = r.stream_position()?;
1273
1274         Ok(Record::Variable(VariableRecord {
1275             offsets: start_offset..end_offset,
1276             width,
1277             name,
1278             print_format,
1279             write_format,
1280             missing_values,
1281             label,
1282         }))
1283     }
1284
1285     pub fn decode<'a>(&'a self, decoder: &Decoder) -> DecodedRecord {
1286         DecodedRecord::Variable(VariableRecord {
1287             offsets: self.offsets.clone(),
1288             width: self.width,
1289             name: decoder.decode(&self.name),
1290             print_format: self.print_format,
1291             write_format: self.write_format,
1292             missing_values: self.missing_values.decode(decoder),
1293             label: self.label.as_ref().map(|label| decoder.decode(label)),
1294         })
1295     }
1296 }
1297
1298 #[derive(Copy, Clone)]
1299 pub struct UntypedValue(pub [u8; 8]);
1300
1301 impl Debug for UntypedValue {
1302     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1303         let little: f64 = Endian::Little.parse(self.0);
1304         let little = format!("{:?}", little);
1305         let big: f64 = Endian::Big.parse(self.0);
1306         let big = format!("{:?}", big);
1307         let number = if little.len() <= big.len() {
1308             little
1309         } else {
1310             big
1311         };
1312         write!(f, "{number}")?;
1313
1314         let string = default_decode(&self.0);
1315         let string = string
1316             .split(|c: char| c == '\0' || c.is_control())
1317             .next()
1318             .unwrap();
1319         write!(f, "{string:?}")?;
1320         Ok(())
1321     }
1322 }
1323
1324 #[derive(Clone)]
1325 pub struct RawString(pub Vec<u8>);
1326
1327 impl From<Vec<u8>> for RawString {
1328     fn from(source: Vec<u8>) -> Self {
1329         Self(source)
1330     }
1331 }
1332
1333 impl From<&[u8]> for RawString {
1334     fn from(source: &[u8]) -> Self {
1335         Self(source.into())
1336     }
1337 }
1338
1339 impl Debug for RawString {
1340     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1341         write!(f, "{:?}", default_decode(self.0.as_slice()))
1342     }
1343 }
1344
1345 #[derive(Copy, Clone)]
1346 pub struct RawStr<const N: usize>(pub [u8; N]);
1347
1348 impl<const N: usize> From<[u8; N]> for RawStr<N> {
1349     fn from(source: [u8; N]) -> Self {
1350         Self(source)
1351     }
1352 }
1353
1354 impl<const N: usize> Debug for RawStr<N> {
1355     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1356         write!(f, "{:?}", default_decode(&self.0))
1357     }
1358 }
1359
1360 #[derive(Clone, Debug)]
1361 pub struct ValueLabel<V, S>
1362 where
1363     V: Debug,
1364     S: Debug,
1365 {
1366     pub value: Value<V>,
1367     pub label: S,
1368 }
1369
1370 #[derive(Clone)]
1371 pub struct ValueLabelRecord<V, S>
1372 where
1373     V: Debug,
1374     S: Debug,
1375 {
1376     /// Range of offsets in file.
1377     pub offsets: Range<u64>,
1378
1379     /// The labels.
1380     pub labels: Vec<ValueLabel<V, S>>,
1381
1382     /// The 1-based indexes of the variable indexes.
1383     pub dict_indexes: Vec<u32>,
1384
1385     /// The types of the variables.
1386     pub var_type: VarType,
1387 }
1388
1389 impl<V, S> Debug for ValueLabelRecord<V, S>
1390 where
1391     V: Debug,
1392     S: Debug,
1393 {
1394     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1395         writeln!(f, "labels: ")?;
1396         for label in self.labels.iter() {
1397             writeln!(f, "{label:?}")?;
1398         }
1399         write!(f, "apply to {} variables", self.var_type)?;
1400         for dict_index in self.dict_indexes.iter() {
1401             write!(f, " #{dict_index}")?;
1402         }
1403         Ok(())
1404     }
1405 }
1406
1407 impl<V, S> Header for ValueLabelRecord<V, S>
1408 where
1409     V: Debug,
1410     S: Debug,
1411 {
1412     fn offsets(&self) -> Range<u64> {
1413         self.offsets.clone()
1414     }
1415 }
1416
1417 impl<V, S> ValueLabelRecord<V, S>
1418 where
1419     V: Debug,
1420     S: Debug,
1421 {
1422     /// Maximum number of value labels in a record.
1423     pub const MAX_LABELS: u32 = u32::MAX / 8;
1424
1425     /// Maximum number of variable indexes in a record.
1426     pub const MAX_INDEXES: u32 = u32::MAX / 8;
1427 }
1428
1429 impl ValueLabelRecord<RawStr<8>, RawString> {
1430     fn read<R: Read + Seek>(
1431         r: &mut R,
1432         endian: Endian,
1433         var_types: &[VarType],
1434         warn: &Box<dyn Fn(Error)>,
1435     ) -> Result<Option<Record>, Error> {
1436         let label_offset = r.stream_position()?;
1437         let n: u32 = endian.parse(read_bytes(r)?);
1438         if n > Self::MAX_LABELS {
1439             return Err(Error::BadNumberOfValueLabels {
1440                 offset: label_offset,
1441                 n,
1442                 max: Self::MAX_LABELS,
1443             });
1444         }
1445
1446         let mut labels = Vec::new();
1447         for _ in 0..n {
1448             let value = UntypedValue(read_bytes(r)?);
1449             let label_len: u8 = endian.parse(read_bytes(r)?);
1450             let label_len = label_len as usize;
1451             let padded_len = Integer::next_multiple_of(&(label_len + 1), &8);
1452
1453             let mut label = read_vec(r, padded_len - 1)?;
1454             label.truncate(label_len);
1455             labels.push((value, RawString(label)));
1456         }
1457
1458         let index_offset = r.stream_position()?;
1459         let rec_type: u32 = endian.parse(read_bytes(r)?);
1460         if rec_type != 4 {
1461             return Err(Error::ExpectedVarIndexRecord {
1462                 offset: index_offset,
1463                 rec_type,
1464             });
1465         }
1466
1467         let n: u32 = endian.parse(read_bytes(r)?);
1468         if n > Self::MAX_INDEXES {
1469             return Err(Error::TooManyVarIndexes {
1470                 offset: index_offset,
1471                 n,
1472                 max: Self::MAX_INDEXES,
1473             });
1474         }
1475
1476         let index_offset = r.stream_position()?;
1477         let mut dict_indexes = Vec::with_capacity(n as usize);
1478         let mut invalid_indexes = Vec::new();
1479         for _ in 0..n {
1480             let index: u32 = endian.parse(read_bytes(r)?);
1481             if index == 0 || index as usize > var_types.len() {
1482                 dict_indexes.push(index);
1483             } else {
1484                 invalid_indexes.push(index);
1485             }
1486         }
1487         if !invalid_indexes.is_empty() {
1488             warn(Error::InvalidVarIndexes {
1489                 offset: index_offset,
1490                 max: var_types.len(),
1491                 invalid: invalid_indexes,
1492             });
1493         }
1494
1495         let Some(&first_index) = dict_indexes.first() else {
1496             warn(Error::NoVarIndexes {
1497                 offset: index_offset,
1498             });
1499             return Ok(None);
1500         };
1501         let var_type = var_types[first_index as usize - 1];
1502         let mut wrong_type_indexes = Vec::new();
1503         dict_indexes.retain(|&index| {
1504             if var_types[index as usize - 1] != var_type {
1505                 wrong_type_indexes.push(index);
1506                 false
1507             } else {
1508                 true
1509             }
1510         });
1511         if !wrong_type_indexes.is_empty() {
1512             warn(Error::MixedVarTypes {
1513                 offset: index_offset,
1514                 var_type,
1515                 wrong_types: wrong_type_indexes,
1516             });
1517         }
1518
1519         let labels = labels
1520             .into_iter()
1521             .map(|(value, label)| ValueLabel {
1522                 value: Value::from_raw(&value, var_type, endian),
1523                 label,
1524             })
1525             .collect();
1526
1527         let end_offset = r.stream_position()?;
1528         Ok(Some(Record::ValueLabel(ValueLabelRecord {
1529             offsets: label_offset..end_offset,
1530             labels,
1531             dict_indexes,
1532             var_type,
1533         })))
1534     }
1535
1536     fn decode<'a>(&'a self, decoder: &Decoder) -> ValueLabelRecord<RawStr<8>, Cow<'a, str>> {
1537         let labels = self
1538             .labels
1539             .iter()
1540             .map(|ValueLabel { value, label }| ValueLabel {
1541                 value: value.clone(),
1542                 label: decoder.decode(label),
1543             })
1544             .collect();
1545         ValueLabelRecord {
1546             offsets: self.offsets.clone(),
1547             labels,
1548             dict_indexes: self.dict_indexes.clone(),
1549             var_type: self.var_type,
1550         }
1551     }
1552 }
1553
1554 #[derive(Clone, Debug)]
1555 pub struct DocumentRecord<S>
1556 where
1557     S: Debug,
1558 {
1559     pub offsets: Range<u64>,
1560
1561     /// The document, as an array of 80-byte lines.
1562     pub lines: Vec<S>,
1563 }
1564
1565 pub type RawDocumentLine = RawStr<DOC_LINE_LEN>;
1566
1567 /// Length of a line in a document.  Document lines are fixed-length and
1568 /// padded on the right with spaces.
1569 pub const DOC_LINE_LEN: usize = 80;
1570
1571 impl DocumentRecord<RawDocumentLine> {
1572     /// Maximum number of lines we will accept in a document.  This is simply
1573     /// the maximum number that will fit in a 32-bit space.
1574     pub const MAX_LINES: usize = i32::MAX as usize / DOC_LINE_LEN;
1575
1576     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1577         let start_offset = r.stream_position()?;
1578         let n: u32 = endian.parse(read_bytes(r)?);
1579         let n = n as usize;
1580         if n > Self::MAX_LINES {
1581             Err(Error::BadDocumentLength {
1582                 offset: start_offset,
1583                 n,
1584                 max: Self::MAX_LINES,
1585             })
1586         } else {
1587             let mut lines = Vec::with_capacity(n);
1588             for _ in 0..n {
1589                 lines.push(RawStr(read_bytes(r)?));
1590             }
1591             let end_offset = r.stream_position()?;
1592             Ok(Record::Document(DocumentRecord {
1593                 offsets: start_offset..end_offset,
1594                 lines,
1595             }))
1596         }
1597     }
1598
1599     pub fn decode<'a>(&'a self, decoder: &Decoder) -> DecodedRecord {
1600         DecodedRecord::Document(DocumentRecord {
1601             offsets: self.offsets.clone(),
1602             lines: self
1603                 .lines
1604                 .iter()
1605                 .map(|s| decoder.decode_slice(&s.0))
1606                 .collect(),
1607         })
1608     }
1609 }
1610
1611 impl<S> Header for DocumentRecord<S>
1612 where
1613     S: Debug,
1614 {
1615     fn offsets(&self) -> Range<u64> {
1616         self.offsets.clone()
1617     }
1618 }
1619
1620 trait ExtensionRecord {
1621     const SUBTYPE: u32;
1622     const SIZE: Option<u32>;
1623     const COUNT: Option<u32>;
1624     const NAME: &'static str;
1625     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error>;
1626 }
1627
1628 #[derive(Clone, Debug)]
1629 pub struct IntegerInfoRecord {
1630     pub offsets: Range<u64>,
1631     pub version: (i32, i32, i32),
1632     pub machine_code: i32,
1633     pub floating_point_rep: i32,
1634     pub compression_code: i32,
1635     pub endianness: i32,
1636     pub character_code: i32,
1637 }
1638
1639 impl ExtensionRecord for IntegerInfoRecord {
1640     const SUBTYPE: u32 = 3;
1641     const SIZE: Option<u32> = Some(4);
1642     const COUNT: Option<u32> = Some(8);
1643     const NAME: &'static str = "integer record";
1644
1645     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
1646         ext.check_size::<Self>()?;
1647
1648         let mut input = &ext.data[..];
1649         let data: Vec<i32> = (0..8)
1650             .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1651             .collect();
1652         Ok(Record::IntegerInfo(IntegerInfoRecord {
1653             offsets: ext.offsets.clone(),
1654             version: (data[0], data[1], data[2]),
1655             machine_code: data[3],
1656             floating_point_rep: data[4],
1657             compression_code: data[5],
1658             endianness: data[6],
1659             character_code: data[7],
1660         }))
1661     }
1662 }
1663
1664 #[derive(Clone, Debug)]
1665 pub struct FloatInfoRecord {
1666     pub sysmis: f64,
1667     pub highest: f64,
1668     pub lowest: f64,
1669 }
1670
1671 impl ExtensionRecord for FloatInfoRecord {
1672     const SUBTYPE: u32 = 4;
1673     const SIZE: Option<u32> = Some(8);
1674     const COUNT: Option<u32> = Some(3);
1675     const NAME: &'static str = "floating point record";
1676
1677     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
1678         ext.check_size::<Self>()?;
1679
1680         let mut input = &ext.data[..];
1681         let data: Vec<f64> = (0..3)
1682             .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1683             .collect();
1684         Ok(Record::FloatInfo(FloatInfoRecord {
1685             sysmis: data[0],
1686             highest: data[1],
1687             lowest: data[2],
1688         }))
1689     }
1690 }
1691
1692 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1693 pub enum CategoryLabels {
1694     VarLabels,
1695     CountedValues,
1696 }
1697
1698 #[derive(Clone, Debug)]
1699 pub enum MultipleResponseType {
1700     MultipleDichotomy {
1701         value: RawString,
1702         labels: CategoryLabels,
1703     },
1704     MultipleCategory,
1705 }
1706
1707 impl MultipleResponseType {
1708     fn parse(input: &[u8]) -> Result<(MultipleResponseType, &[u8]), Error> {
1709         let (mr_type, input) = match input.split_first() {
1710             Some((b'C', input)) => (MultipleResponseType::MultipleCategory, input),
1711             Some((b'D', input)) => {
1712                 let (value, input) = parse_counted_string(input)?;
1713                 (
1714                     MultipleResponseType::MultipleDichotomy {
1715                         value,
1716                         labels: CategoryLabels::VarLabels,
1717                     },
1718                     input,
1719                 )
1720             }
1721             Some((b'E', input)) => {
1722                 let (labels, input) = if let Some(rest) = input.strip_prefix(b" 1 ") {
1723                     (CategoryLabels::CountedValues, rest)
1724                 } else if let Some(rest) = input.strip_prefix(b" 11 ") {
1725                     (CategoryLabels::VarLabels, rest)
1726                 } else {
1727                     return Err(Error::TBD);
1728                 };
1729                 let (value, input) = parse_counted_string(input)?;
1730                 (
1731                     MultipleResponseType::MultipleDichotomy { value, labels },
1732                     input,
1733                 )
1734             }
1735             _ => return Err(Error::TBD),
1736         };
1737         Ok((mr_type, input))
1738     }
1739 }
1740
1741 #[derive(Clone, Debug)]
1742 pub struct MultipleResponseSet<I, S>
1743 where
1744     I: Debug,
1745     S: Debug,
1746 {
1747     pub name: I,
1748     pub label: S,
1749     pub mr_type: MultipleResponseType,
1750     pub short_names: Vec<I>,
1751 }
1752
1753 impl MultipleResponseSet<RawString, RawString> {
1754     fn parse(input: &[u8]) -> Result<(Self, &[u8]), Error> {
1755         let Some(equals) = input.iter().position(|&b| b == b'=') else {
1756             return Err(Error::TBD);
1757         };
1758         let (name, input) = input.split_at(equals);
1759         let (mr_type, input) = MultipleResponseType::parse(input)?;
1760         let Some(input) = input.strip_prefix(b" ") else {
1761             return Err(Error::TBD);
1762         };
1763         let (label, mut input) = parse_counted_string(input)?;
1764         let mut vars = Vec::new();
1765         while input.first() != Some(&b'\n') {
1766             match input.split_first() {
1767                 Some((b' ', rest)) => {
1768                     let Some(length) = rest.iter().position(|b| b" \n".contains(b)) else {
1769                         return Err(Error::TBD);
1770                     };
1771                     let (var, rest) = rest.split_at(length);
1772                     if !var.is_empty() {
1773                         vars.push(var.into());
1774                     }
1775                     input = rest;
1776                 }
1777                 _ => return Err(Error::TBD),
1778             }
1779         }
1780         while input.first() == Some(&b'\n') {
1781             input = &input[1..];
1782         }
1783         Ok((
1784             MultipleResponseSet {
1785                 name: name.into(),
1786                 label,
1787                 mr_type,
1788                 short_names: vars,
1789             },
1790             input,
1791         ))
1792     }
1793
1794     fn decode<'a>(
1795         &'a self,
1796         decoder: &Decoder,
1797     ) -> Result<MultipleResponseSet<Identifier, Cow<'a, str>>, Error> {
1798         let mut short_names = Vec::with_capacity(self.short_names.len());
1799         for short_name in self.short_names.iter() {
1800             if let Some(short_name) = decoder
1801                 .decode_identifier(short_name)
1802                 .map_err(|err| Error::InvalidMrSetName(err))
1803                 .warn_on_error(&decoder.warn)
1804             {
1805                 short_names.push(short_name);
1806             }
1807         }
1808         Ok(MultipleResponseSet {
1809             name: decoder
1810                 .decode_identifier(&self.name)
1811                 .map_err(|err| Error::InvalidMrSetVariableName(err))?,
1812             label: decoder.decode(&self.label),
1813             mr_type: self.mr_type.clone(),
1814             short_names: short_names,
1815         })
1816     }
1817 }
1818
1819 #[derive(Clone, Debug)]
1820 pub struct MultipleResponseRecord<I, S>(pub Vec<MultipleResponseSet<I, S>>)
1821 where
1822     I: Debug,
1823     S: Debug;
1824
1825 impl ExtensionRecord for MultipleResponseRecord<RawString, RawString> {
1826     const SUBTYPE: u32 = 7;
1827     const SIZE: Option<u32> = Some(1);
1828     const COUNT: Option<u32> = None;
1829     const NAME: &'static str = "multiple response set record";
1830
1831     fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Error> {
1832         ext.check_size::<Self>()?;
1833
1834         let mut input = &ext.data[..];
1835         let mut sets = Vec::new();
1836         while !input.is_empty() {
1837             let (set, rest) = MultipleResponseSet::parse(input)?;
1838             sets.push(set);
1839             input = rest;
1840         }
1841         Ok(Record::MultipleResponse(MultipleResponseRecord(sets)))
1842     }
1843 }
1844
1845 impl MultipleResponseRecord<RawString, RawString> {
1846     fn decode<'a>(&'a self, decoder: &Decoder) -> DecodedRecord {
1847         let mut sets = Vec::new();
1848         for set in self.0.iter() {
1849             if let Some(set) = set.decode(decoder).warn_on_error(&decoder.warn) {
1850                 sets.push(set);
1851             }
1852         }
1853         DecodedRecord::MultipleResponse(MultipleResponseRecord(sets))
1854     }
1855 }
1856
1857 fn parse_counted_string(input: &[u8]) -> Result<(RawString, &[u8]), Error> {
1858     let Some(space) = input.iter().position(|&b| b == b' ') else {
1859         return Err(Error::TBD);
1860     };
1861     let Ok(length) = from_utf8(&input[..space]) else {
1862         return Err(Error::TBD);
1863     };
1864     let Ok(length): Result<usize, _> = length.parse() else {
1865         return Err(Error::TBD);
1866     };
1867
1868     let input = &input[space + 1..];
1869     if input.len() < length {
1870         return Err(Error::TBD);
1871     };
1872
1873     let (string, rest) = input.split_at(length);
1874     Ok((string.into(), rest))
1875 }
1876
1877 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1878 pub enum Measure {
1879     Nominal,
1880     Ordinal,
1881     Scale,
1882 }
1883
1884 impl Measure {
1885     pub fn default_for_type(var_type: VarType) -> Option<Measure> {
1886         match var_type {
1887             VarType::Numeric => None,
1888             VarType::String => Some(Self::Nominal),
1889         }
1890     }
1891
1892     fn try_decode(source: u32) -> Result<Option<Measure>, Error> {
1893         match source {
1894             0 => Ok(None),
1895             1 => Ok(Some(Measure::Nominal)),
1896             2 => Ok(Some(Measure::Ordinal)),
1897             3 => Ok(Some(Measure::Scale)),
1898             _ => Err(Error::InvalidMeasurement(source)),
1899         }
1900     }
1901 }
1902
1903 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1904 pub enum Alignment {
1905     Left,
1906     Right,
1907     Center,
1908 }
1909
1910 impl Alignment {
1911     fn try_decode(source: u32) -> Result<Option<Alignment>, Error> {
1912         match source {
1913             0 => Ok(None),
1914             1 => Ok(Some(Alignment::Left)),
1915             2 => Ok(Some(Alignment::Right)),
1916             3 => Ok(Some(Alignment::Center)),
1917             _ => Err(Error::InvalidAlignment(source)),
1918         }
1919     }
1920
1921     pub fn default_for_type(var_type: VarType) -> Self {
1922         match var_type {
1923             VarType::Numeric => Self::Right,
1924             VarType::String => Self::Left,
1925         }
1926     }
1927 }
1928
1929 #[derive(Clone, Debug)]
1930 pub struct VarDisplay {
1931     pub measure: Option<Measure>,
1932     pub width: Option<u32>,
1933     pub alignment: Option<Alignment>,
1934 }
1935
1936 #[derive(Clone, Debug)]
1937 pub struct VarDisplayRecord(pub Vec<VarDisplay>);
1938
1939 impl VarDisplayRecord {
1940     const SUBTYPE: u32 = 11;
1941
1942     fn parse(
1943         ext: &Extension,
1944         n_vars: usize,
1945         endian: Endian,
1946         warn: &Box<dyn Fn(Error)>,
1947     ) -> Result<Record, Error> {
1948         if ext.size != 4 {
1949             return Err(Error::BadRecordSize {
1950                 offset: ext.offsets.start,
1951                 record: String::from("variable display record"),
1952                 size: ext.size,
1953                 expected_size: 4,
1954             });
1955         }
1956
1957         let has_width = if ext.count as usize == 3 * n_vars {
1958             true
1959         } else if ext.count as usize == 2 * n_vars {
1960             false
1961         } else {
1962             return Err(Error::TBD);
1963         };
1964
1965         let mut var_displays = Vec::new();
1966         let mut input = &ext.data[..];
1967         for _ in 0..n_vars {
1968             let measure = Measure::try_decode(endian.parse(read_bytes(&mut input).unwrap()))
1969                 .warn_on_error(&warn)
1970                 .flatten();
1971             let width = has_width.then(|| endian.parse(read_bytes(&mut input).unwrap()));
1972             let alignment = Alignment::try_decode(endian.parse(read_bytes(&mut input).unwrap()))
1973                 .warn_on_error(&warn)
1974                 .flatten();
1975             var_displays.push(VarDisplay {
1976                 measure,
1977                 width,
1978                 alignment,
1979             });
1980         }
1981         Ok(Record::VarDisplay(VarDisplayRecord(var_displays)))
1982     }
1983 }
1984
1985 #[derive(Clone, Debug)]
1986 pub struct LongStringMissingValues<N, V>
1987 where
1988     N: Debug,
1989     V: Debug,
1990 {
1991     /// Variable name.
1992     pub var_name: N,
1993
1994     /// Missing values.
1995     pub missing_values: MissingValues<V>,
1996 }
1997
1998 impl LongStringMissingValues<RawString, RawStr<8>> {
1999     fn decode<'a>(
2000         &self,
2001         decoder: &Decoder,
2002     ) -> Result<LongStringMissingValues<Identifier, String>, IdError> {
2003         Ok(LongStringMissingValues {
2004             var_name: decoder.decode_identifier(&self.var_name)?,
2005             missing_values: self.missing_values.decode(decoder),
2006         })
2007     }
2008 }
2009
2010 #[derive(Clone, Debug)]
2011 pub struct LongStringMissingValueRecord<N, V>(pub Vec<LongStringMissingValues<N, V>>)
2012 where
2013     N: Debug,
2014     V: Debug;
2015
2016 impl ExtensionRecord for LongStringMissingValueRecord<RawString, RawStr<8>> {
2017     const SUBTYPE: u32 = 22;
2018     const SIZE: Option<u32> = Some(1);
2019     const COUNT: Option<u32> = None;
2020     const NAME: &'static str = "long string missing values record";
2021
2022     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
2023         ext.check_size::<Self>()?;
2024
2025         let mut input = &ext.data[..];
2026         let mut missing_value_set = Vec::new();
2027         while !input.is_empty() {
2028             let var_name = read_string(&mut input, endian)?;
2029             let n_missing_values: u8 = endian.parse(read_bytes(&mut input)?);
2030             let value_len: u32 = endian.parse(read_bytes(&mut input)?);
2031             if value_len != 8 {
2032                 let offset = (ext.data.len() - input.len() - 8) as u64 + ext.offsets.start;
2033                 return Err(Error::BadLongMissingValueLength {
2034                     record_offset: ext.offsets.start,
2035                     offset,
2036                     value_len,
2037                 });
2038             }
2039             let mut values = Vec::new();
2040             for i in 0..n_missing_values {
2041                 let value: [u8; 8] = read_bytes(&mut input)?;
2042                 let numeric_value: u64 = endian.parse(value);
2043                 let value = if i > 0 && numeric_value == 8 {
2044                     // Tolerate files written by old, buggy versions of PSPP
2045                     // where we believed that the value_length was repeated
2046                     // before each missing value.
2047                     read_bytes(&mut input)?
2048                 } else {
2049                     value
2050                 };
2051                 values.push(Value::String(RawStr(value)));
2052             }
2053             let missing_values = MissingValues {
2054                 values,
2055                 range: None,
2056             };
2057             missing_value_set.push(LongStringMissingValues {
2058                 var_name,
2059                 missing_values,
2060             });
2061         }
2062         Ok(Record::LongStringMissingValues(
2063             LongStringMissingValueRecord(missing_value_set),
2064         ))
2065     }
2066 }
2067
2068 impl LongStringMissingValueRecord<RawString, RawStr<8>> {
2069     pub fn decode<'a>(
2070         &self,
2071         decoder: &Decoder,
2072     ) -> LongStringMissingValueRecord<Identifier, String> {
2073         let mut mvs = Vec::with_capacity(self.0.len());
2074         for mv in self.0.iter() {
2075             if let Some(mv) = mv
2076                 .decode(decoder)
2077                 .map_err(|err| Error::InvalidLongStringMissingValueVariableName(err))
2078                 .warn_on_error(&decoder.warn)
2079             {
2080                 mvs.push(mv);
2081             }
2082         }
2083         LongStringMissingValueRecord(mvs)
2084     }
2085 }
2086
2087 #[derive(Clone, Debug)]
2088 pub struct EncodingRecord(pub String);
2089
2090 impl ExtensionRecord for EncodingRecord {
2091     const SUBTYPE: u32 = 20;
2092     const SIZE: Option<u32> = Some(1);
2093     const COUNT: Option<u32> = None;
2094     const NAME: &'static str = "encoding record";
2095
2096     fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Error> {
2097         ext.check_size::<Self>()?;
2098
2099         Ok(Record::Encoding(EncodingRecord(
2100             String::from_utf8(ext.data.clone()).map_err(|_| Error::BadEncodingName {
2101                 offset: ext.offsets.start,
2102             })?,
2103         )))
2104     }
2105 }
2106
2107 #[derive(Copy, Clone, Debug)]
2108 pub struct NumberOfCasesRecord {
2109     /// Always observed as 1.
2110     pub one: u64,
2111
2112     /// Number of cases.
2113     pub n_cases: u64,
2114 }
2115
2116 impl ExtensionRecord for NumberOfCasesRecord {
2117     const SUBTYPE: u32 = 16;
2118     const SIZE: Option<u32> = Some(8);
2119     const COUNT: Option<u32> = Some(2);
2120     const NAME: &'static str = "extended number of cases record";
2121
2122     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
2123         ext.check_size::<Self>()?;
2124
2125         let mut input = &ext.data[..];
2126         let one = endian.parse(read_bytes(&mut input)?);
2127         let n_cases = endian.parse(read_bytes(&mut input)?);
2128
2129         Ok(Record::NumberOfCases(NumberOfCasesRecord { one, n_cases }))
2130     }
2131 }
2132
2133 #[derive(Clone, Debug)]
2134 pub struct TextRecord {
2135     pub offsets: Range<u64>,
2136
2137     /// Type of record.
2138     pub rec_type: TextRecordType,
2139
2140     /// The text content of the record.
2141     pub text: RawString,
2142 }
2143
2144 #[derive(Clone, Copy, Debug)]
2145 pub enum TextRecordType {
2146     VariableSets,
2147     ProductInfo,
2148     LongNames,
2149     VeryLongStrings,
2150     FileAttributes,
2151     VariableAttributes,
2152 }
2153
2154 impl TextRecord {
2155     fn new(extension: Extension, rec_type: TextRecordType) -> Self {
2156         Self {
2157             offsets: extension.offsets,
2158             rec_type,
2159             text: extension.data.into(),
2160         }
2161     }
2162     pub fn decode<'a>(&self, decoder: &Decoder) -> Result<DecodedRecord, Error> {
2163         match self.rec_type {
2164             TextRecordType::VariableSets => Ok(DecodedRecord::VariableSets(
2165                 VariableSetRecord::decode(self, decoder),
2166             )),
2167             TextRecordType::ProductInfo => Ok(DecodedRecord::ProductInfo(
2168                 ProductInfoRecord::decode(self, decoder),
2169             )),
2170             TextRecordType::LongNames => Ok(DecodedRecord::LongNames(LongNamesRecord::decode(
2171                 self, decoder,
2172             ))),
2173             TextRecordType::VeryLongStrings => Ok(DecodedRecord::VeryLongStrings(
2174                 VeryLongStringsRecord::decode(self, decoder),
2175             )),
2176             TextRecordType::FileAttributes => Ok(DecodedRecord::FileAttributes(
2177                 FileAttributeRecord::decode(self, decoder),
2178             )),
2179             TextRecordType::VariableAttributes => Ok(DecodedRecord::VariableAttributes(
2180                 VariableAttributeRecord::decode(self, decoder),
2181             )),
2182         }
2183     }
2184 }
2185
2186 #[derive(Clone, Debug)]
2187 pub struct VeryLongString {
2188     pub short_name: Identifier,
2189     pub length: u16,
2190 }
2191
2192 impl VeryLongString {
2193     fn parse(decoder: &Decoder, input: &str) -> Result<VeryLongString, Error> {
2194         let Some((short_name, length)) = input.split_once('=') else {
2195             return Err(Error::TBD);
2196         };
2197         let short_name = decoder
2198             .new_identifier(short_name)
2199             .map_err(Error::InvalidLongStringName)?;
2200         let length = length.parse().map_err(|_| Error::TBD)?;
2201         Ok(VeryLongString { short_name, length })
2202     }
2203 }
2204
2205 #[derive(Clone, Debug)]
2206 pub struct VeryLongStringsRecord(Vec<VeryLongString>);
2207
2208 impl VeryLongStringsRecord {
2209     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2210         let input = decoder.decode(&source.text);
2211         let mut very_long_strings = Vec::new();
2212         for tuple in input
2213             .split('\0')
2214             .map(|s| s.trim_end_matches('\t'))
2215             .filter(|s| !s.is_empty())
2216         {
2217             if let Some(vls) = VeryLongString::parse(decoder, tuple).warn_on_error(&decoder.warn) {
2218                 very_long_strings.push(vls)
2219             }
2220         }
2221         VeryLongStringsRecord(very_long_strings)
2222     }
2223 }
2224
2225 #[derive(Clone, Debug)]
2226 pub struct Attribute {
2227     pub name: Identifier,
2228     pub values: Vec<String>,
2229 }
2230
2231 impl Attribute {
2232     fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(Attribute, &'a str), Error> {
2233         let Some((name, mut input)) = input.split_once('(') else {
2234             return Err(Error::TBD);
2235         };
2236         let name = decoder
2237             .new_identifier(name)
2238             .map_err(Error::InvalidAttributeName)?;
2239         let mut values = Vec::new();
2240         loop {
2241             let Some((value, rest)) = input.split_once('\n') else {
2242                 return Err(Error::TBD);
2243             };
2244             if let Some(stripped) = value
2245                 .strip_prefix('\'')
2246                 .and_then(|value| value.strip_suffix('\''))
2247             {
2248                 values.push(stripped.into());
2249             } else {
2250                 decoder.warn(Error::TBD);
2251                 values.push(value.into());
2252             }
2253             if let Some(rest) = rest.strip_prefix(')') {
2254                 let attribute = Attribute { name, values };
2255                 return Ok((attribute, rest));
2256             };
2257             input = rest;
2258         }
2259     }
2260 }
2261
2262 #[derive(Clone, Debug)]
2263 pub struct AttributeSet(pub HashMap<Identifier, Vec<String>>);
2264
2265 impl AttributeSet {
2266     fn parse<'a>(
2267         decoder: &Decoder,
2268         mut input: &'a str,
2269         sentinel: Option<char>,
2270     ) -> Result<(AttributeSet, &'a str), Error> {
2271         let mut attributes = HashMap::new();
2272         let rest = loop {
2273             match input.chars().next() {
2274                 None => break input,
2275                 c if c == sentinel => break &input[1..],
2276                 _ => {
2277                     let (attribute, rest) = Attribute::parse(decoder, input)?;
2278                     // XXX report duplicate name
2279                     attributes.insert(attribute.name, attribute.values);
2280                     input = rest;
2281                 }
2282             }
2283         };
2284         Ok((AttributeSet(attributes), rest))
2285     }
2286 }
2287
2288 impl Default for AttributeSet {
2289     fn default() -> Self {
2290         Self(HashMap::default())
2291     }
2292 }
2293
2294 #[derive(Clone, Debug)]
2295 pub struct FileAttributeRecord(AttributeSet);
2296
2297 impl FileAttributeRecord {
2298     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2299         let input = decoder.decode(&source.text);
2300         match AttributeSet::parse(decoder, &input, None).warn_on_error(&decoder.warn) {
2301             Some((set, rest)) => {
2302                 if !rest.is_empty() {
2303                     decoder.warn(Error::TBD);
2304                 }
2305                 FileAttributeRecord(set)
2306             }
2307             None => FileAttributeRecord::default(),
2308         }
2309     }
2310 }
2311
2312 impl Default for FileAttributeRecord {
2313     fn default() -> Self {
2314         Self(AttributeSet::default())
2315     }
2316 }
2317
2318 #[derive(Clone, Debug)]
2319 pub struct VarAttributeSet {
2320     pub long_var_name: Identifier,
2321     pub attributes: AttributeSet,
2322 }
2323
2324 impl VarAttributeSet {
2325     fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(VarAttributeSet, &'a str), Error> {
2326         let Some((long_var_name, rest)) = input.split_once(':') else {
2327             return Err(Error::TBD);
2328         };
2329         let long_var_name = decoder
2330             .new_identifier(long_var_name)
2331             .map_err(Error::InvalidAttributeVariableName)?;
2332         let (attributes, rest) = AttributeSet::parse(decoder, rest, Some('/'))?;
2333         let var_attribute = VarAttributeSet {
2334             long_var_name,
2335             attributes,
2336         };
2337         Ok((var_attribute, rest))
2338     }
2339 }
2340
2341 #[derive(Clone, Debug)]
2342 pub struct VariableAttributeRecord(Vec<VarAttributeSet>);
2343
2344 impl VariableAttributeRecord {
2345     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2346         let decoded = decoder.decode(&source.text);
2347         let mut input = decoded.as_ref();
2348         let mut var_attribute_sets = Vec::new();
2349         while !input.is_empty() {
2350             let Some((var_attribute, rest)) =
2351                 VarAttributeSet::parse(decoder, &input).warn_on_error(&decoder.warn)
2352             else {
2353                 break;
2354             };
2355             var_attribute_sets.push(var_attribute);
2356             input = rest.into();
2357         }
2358         VariableAttributeRecord(var_attribute_sets)
2359     }
2360 }
2361
2362 #[derive(Clone, Debug)]
2363 pub struct LongName {
2364     pub short_name: Identifier,
2365     pub long_name: Identifier,
2366 }
2367
2368 impl LongName {
2369     fn parse(input: &str, decoder: &Decoder) -> Result<Self, Error> {
2370         let Some((short_name, long_name)) = input.split_once('=') else {
2371             return Err(Error::TBD);
2372         };
2373         let short_name = decoder
2374             .new_identifier(short_name)
2375             .map_err(Error::InvalidShortName)?;
2376         let long_name = decoder
2377             .new_identifier(long_name)
2378             .map_err(Error::InvalidLongName)?;
2379         Ok(LongName {
2380             short_name,
2381             long_name,
2382         })
2383     }
2384 }
2385
2386 #[derive(Clone, Debug)]
2387 pub struct LongNamesRecord(Vec<LongName>);
2388
2389 impl LongNamesRecord {
2390     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2391         let input = decoder.decode(&source.text);
2392         let mut names = Vec::new();
2393         for pair in input.split('\t').filter(|s| !s.is_empty()) {
2394             if let Some(long_name) = LongName::parse(pair, decoder).warn_on_error(&decoder.warn) {
2395                 names.push(long_name);
2396             }
2397         }
2398         LongNamesRecord(names)
2399     }
2400 }
2401
2402 #[derive(Clone, Debug)]
2403 pub struct ProductInfoRecord(pub String);
2404
2405 impl ProductInfoRecord {
2406     const NAME: &'static str = "extra product info";
2407     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2408         Self(decoder.decode(&source.text).into())
2409     }
2410 }
2411 #[derive(Clone, Debug)]
2412 pub struct VariableSet {
2413     pub name: String,
2414     pub vars: Vec<Identifier>,
2415 }
2416
2417 impl VariableSet {
2418     fn parse(input: &str, decoder: &Decoder) -> Result<Self, Error> {
2419         let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
2420         let mut vars = Vec::new();
2421         for var in input.split_ascii_whitespace() {
2422             if let Some(identifier) = decoder
2423                 .new_identifier(var)
2424                 .map_err(Error::InvalidVariableSetName)
2425                 .warn_on_error(&decoder.warn)
2426             {
2427                 vars.push(identifier);
2428             }
2429         }
2430         Ok(VariableSet {
2431             name: name.into(),
2432             vars,
2433         })
2434     }
2435 }
2436
2437 #[derive(Clone, Debug)]
2438 pub struct VariableSetRecord {
2439     pub offsets: Range<u64>,
2440     pub sets: Vec<VariableSet>,
2441 }
2442
2443 impl VariableSetRecord {
2444     fn decode(source: &TextRecord, decoder: &Decoder) -> VariableSetRecord {
2445         let mut sets = Vec::new();
2446         let input = decoder.decode(&source.text);
2447         for line in input.lines() {
2448             if let Some(set) = VariableSet::parse(line, decoder).warn_on_error(&decoder.warn) {
2449                 sets.push(set)
2450             }
2451         }
2452         VariableSetRecord {
2453             offsets: source.offsets.clone(),
2454             sets,
2455         }
2456     }
2457 }
2458
2459 trait WarnOnError<T> {
2460     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T>;
2461 }
2462 impl<T> WarnOnError<T> for Result<T, Error> {
2463     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T> {
2464         match self {
2465             Ok(result) => Some(result),
2466             Err(error) => {
2467                 warn(error);
2468                 None
2469             }
2470         }
2471     }
2472 }
2473
2474 #[derive(Clone, Debug)]
2475 pub struct Extension {
2476     pub offsets: Range<u64>,
2477
2478     /// Record subtype.
2479     pub subtype: u32,
2480
2481     /// Size of each data element.
2482     pub size: u32,
2483
2484     /// Number of data elements.
2485     pub count: u32,
2486
2487     /// `size * count` bytes of data.
2488     pub data: Vec<u8>,
2489 }
2490
2491 impl Extension {
2492     fn check_size<E: ExtensionRecord>(&self) -> Result<(), Error> {
2493         if let Some(expected_size) = E::SIZE {
2494             if self.size != expected_size {
2495                 return Err(Error::BadRecordSize {
2496                     offset: self.offsets.start,
2497                     record: E::NAME.into(),
2498                     size: self.size,
2499                     expected_size,
2500                 });
2501             }
2502         }
2503         if let Some(expected_count) = E::COUNT {
2504             if self.count != expected_count {
2505                 return Err(Error::BadRecordCount {
2506                     offset: self.offsets.start,
2507                     record: E::NAME.into(),
2508                     count: self.count,
2509                     expected_count,
2510                 });
2511             }
2512         }
2513         Ok(())
2514     }
2515
2516     fn read<R: Read + Seek>(
2517         r: &mut R,
2518         endian: Endian,
2519         n_vars: usize,
2520         warn: &Box<dyn Fn(Error)>,
2521     ) -> Result<Option<Record>, Error> {
2522         let subtype = endian.parse(read_bytes(r)?);
2523         let header_offset = r.stream_position()?;
2524         let size: u32 = endian.parse(read_bytes(r)?);
2525         let count = endian.parse(read_bytes(r)?);
2526         let Some(product) = size.checked_mul(count) else {
2527             return Err(Error::ExtensionRecordTooLarge {
2528                 offset: header_offset,
2529                 subtype,
2530                 size,
2531                 count,
2532             });
2533         };
2534         let start_offset = r.stream_position()?;
2535         let data = read_vec(r, product as usize)?;
2536         let end_offset = start_offset + product as u64;
2537         let extension = Extension {
2538             offsets: start_offset..end_offset,
2539             subtype,
2540             size,
2541             count,
2542             data,
2543         };
2544         let result = match subtype {
2545             IntegerInfoRecord::SUBTYPE => IntegerInfoRecord::parse(&extension, endian),
2546             FloatInfoRecord::SUBTYPE => FloatInfoRecord::parse(&extension, endian),
2547             VarDisplayRecord::SUBTYPE => VarDisplayRecord::parse(&extension, n_vars, endian, warn),
2548             MultipleResponseRecord::SUBTYPE | 19 => {
2549                 MultipleResponseRecord::parse(&extension, endian)
2550             }
2551             LongStringValueLabelRecord::SUBTYPE => {
2552                 LongStringValueLabelRecord::parse(&extension, endian)
2553             }
2554             EncodingRecord::SUBTYPE => EncodingRecord::parse(&extension, endian),
2555             NumberOfCasesRecord::SUBTYPE => NumberOfCasesRecord::parse(&extension, endian),
2556             5 => Ok(Record::Text(TextRecord::new(
2557                 extension,
2558                 TextRecordType::VariableSets,
2559             ))),
2560             10 => Ok(Record::Text(TextRecord::new(
2561                 extension,
2562                 TextRecordType::ProductInfo,
2563             ))),
2564             13 => Ok(Record::Text(TextRecord::new(
2565                 extension,
2566                 TextRecordType::LongNames,
2567             ))),
2568             14 => Ok(Record::Text(TextRecord::new(
2569                 extension,
2570                 TextRecordType::VeryLongStrings,
2571             ))),
2572             17 => Ok(Record::Text(TextRecord::new(
2573                 extension,
2574                 TextRecordType::FileAttributes,
2575             ))),
2576             18 => Ok(Record::Text(TextRecord::new(
2577                 extension,
2578                 TextRecordType::VariableAttributes,
2579             ))),
2580             _ => Ok(Record::OtherExtension(extension)),
2581         };
2582         match result {
2583             Ok(result) => Ok(Some(result)),
2584             Err(error) => {
2585                 warn(error);
2586                 Ok(None)
2587             }
2588         }
2589     }
2590 }
2591
2592 #[derive(Clone, Debug)]
2593 pub struct ZHeader {
2594     /// File offset to the start of the record.
2595     pub offset: u64,
2596
2597     /// File offset to the ZLIB data header.
2598     pub zheader_offset: u64,
2599
2600     /// File offset to the ZLIB trailer.
2601     pub ztrailer_offset: u64,
2602
2603     /// Length of the ZLIB trailer in bytes.
2604     pub ztrailer_len: u64,
2605 }
2606
2607 impl ZHeader {
2608     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZHeader, Error> {
2609         let offset = r.stream_position()?;
2610         let zheader_offset: u64 = endian.parse(read_bytes(r)?);
2611         let ztrailer_offset: u64 = endian.parse(read_bytes(r)?);
2612         let ztrailer_len: u64 = endian.parse(read_bytes(r)?);
2613
2614         Ok(ZHeader {
2615             offset,
2616             zheader_offset,
2617             ztrailer_offset,
2618             ztrailer_len,
2619         })
2620     }
2621 }
2622
2623 #[derive(Clone, Debug)]
2624 pub struct ZTrailer {
2625     /// File offset to the start of the record.
2626     pub offset: u64,
2627
2628     /// Compression bias as a negative integer, e.g. -100.
2629     pub int_bias: i64,
2630
2631     /// Always observed as zero.
2632     pub zero: u64,
2633
2634     /// Uncompressed size of each block, except possibly the last.  Only
2635     /// `0x3ff000` has been observed so far.
2636     pub block_size: u32,
2637
2638     /// Block descriptors, always `(ztrailer_len - 24) / 24)` of them.
2639     pub blocks: Vec<ZBlock>,
2640 }
2641
2642 #[derive(Clone, Debug)]
2643 pub struct ZBlock {
2644     /// Offset of block of data if simple compression were used.
2645     pub uncompressed_ofs: u64,
2646
2647     /// Actual offset within the file of the compressed data block.
2648     pub compressed_ofs: u64,
2649
2650     /// The number of bytes in this data block after decompression.  This is
2651     /// `block_size` in every data block but the last, which may be smaller.
2652     pub uncompressed_size: u32,
2653
2654     /// The number of bytes in this data block, as stored compressed in this
2655     /// file.
2656     pub compressed_size: u32,
2657 }
2658
2659 impl ZBlock {
2660     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZBlock, Error> {
2661         Ok(ZBlock {
2662             uncompressed_ofs: endian.parse(read_bytes(r)?),
2663             compressed_ofs: endian.parse(read_bytes(r)?),
2664             uncompressed_size: endian.parse(read_bytes(r)?),
2665             compressed_size: endian.parse(read_bytes(r)?),
2666         })
2667     }
2668 }
2669
2670 impl ZTrailer {
2671     fn read<R: Read + Seek>(
2672         reader: &mut R,
2673         endian: Endian,
2674         ztrailer_ofs: u64,
2675         ztrailer_len: u64,
2676     ) -> Result<Option<ZTrailer>, Error> {
2677         let start_offset = reader.stream_position()?;
2678         if reader.seek(SeekFrom::Start(ztrailer_ofs)).is_err() {
2679             return Ok(None);
2680         }
2681         let int_bias = endian.parse(read_bytes(reader)?);
2682         let zero = endian.parse(read_bytes(reader)?);
2683         let block_size = endian.parse(read_bytes(reader)?);
2684         let n_blocks: u32 = endian.parse(read_bytes(reader)?);
2685         let expected_n_blocks = (ztrailer_len - 24) / 24;
2686         if n_blocks as u64 != expected_n_blocks {
2687             return Err(Error::BadZlibTrailerNBlocks {
2688                 offset: ztrailer_ofs,
2689                 n_blocks,
2690                 expected_n_blocks,
2691                 ztrailer_len,
2692             });
2693         }
2694         let blocks = (0..n_blocks)
2695             .map(|_| ZBlock::read(reader, endian))
2696             .collect::<Result<Vec<_>, _>>()?;
2697         reader.seek(SeekFrom::Start(start_offset))?;
2698         Ok(Some(ZTrailer {
2699             offset: ztrailer_ofs,
2700             int_bias,
2701             zero,
2702             block_size,
2703             blocks,
2704         }))
2705     }
2706 }
2707
2708 fn try_read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<Option<[u8; N]>, IoError> {
2709     let mut buf = [0; N];
2710     let n = r.read(&mut buf)?;
2711     if n > 0 {
2712         if n < N {
2713             r.read_exact(&mut buf[n..])?;
2714         }
2715         Ok(Some(buf))
2716     } else {
2717         Ok(None)
2718     }
2719 }
2720
2721 fn read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<[u8; N], IoError> {
2722     let mut buf = [0; N];
2723     r.read_exact(&mut buf)?;
2724     Ok(buf)
2725 }
2726
2727 fn read_vec<R: Read>(r: &mut R, n: usize) -> Result<Vec<u8>, IoError> {
2728     let mut vec = vec![0; n];
2729     r.read_exact(&mut vec)?;
2730     Ok(vec)
2731 }
2732
2733 fn read_string<R: Read>(r: &mut R, endian: Endian) -> Result<RawString, IoError> {
2734     let length: u32 = endian.parse(read_bytes(r)?);
2735     Ok(read_vec(r, length as usize)?.into())
2736 }
2737
2738 #[derive(Clone, Debug)]
2739 pub struct LongStringValueLabels<N, S>
2740 where
2741     S: Debug,
2742 {
2743     pub var_name: N,
2744     pub width: u32,
2745
2746     /// `(value, label)` pairs, where each value is `width` bytes.
2747     pub labels: Vec<(S, S)>,
2748 }
2749
2750 impl LongStringValueLabels<RawString, RawString> {
2751     fn decode<'a>(
2752         &'a self,
2753         decoder: &Decoder,
2754     ) -> Result<LongStringValueLabels<Identifier, Cow<'a, str>>, Error> {
2755         let var_name = decoder.decode(&self.var_name);
2756         let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
2757             .map_err(Error::InvalidLongStringValueLabelName)?;
2758
2759         let mut labels = Vec::with_capacity(self.labels.len());
2760         for (value, label) in self.labels.iter() {
2761             let value = decoder.decode_exact_length(&value.0);
2762             let label = decoder.decode(&label);
2763             labels.push((value, label));
2764         }
2765
2766         Ok(LongStringValueLabels {
2767             var_name,
2768             width: self.width,
2769             labels,
2770         })
2771     }
2772 }
2773
2774 #[derive(Clone, Debug)]
2775 pub struct LongStringValueLabelRecord<N, S>(pub Vec<LongStringValueLabels<N, S>>)
2776 where
2777     N: Debug,
2778     S: Debug;
2779
2780 impl ExtensionRecord for LongStringValueLabelRecord<RawString, RawString> {
2781     const SUBTYPE: u32 = 21;
2782     const SIZE: Option<u32> = Some(1);
2783     const COUNT: Option<u32> = None;
2784     const NAME: &'static str = "long string value labels record";
2785
2786     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
2787         ext.check_size::<Self>()?;
2788
2789         let mut input = &ext.data[..];
2790         let mut label_set = Vec::new();
2791         while !input.is_empty() {
2792             let var_name = read_string(&mut input, endian)?;
2793             let width: u32 = endian.parse(read_bytes(&mut input)?);
2794             let n_labels: u32 = endian.parse(read_bytes(&mut input)?);
2795             let mut labels = Vec::new();
2796             for _ in 0..n_labels {
2797                 let value = read_string(&mut input, endian)?;
2798                 let label = read_string(&mut input, endian)?;
2799                 labels.push((value, label));
2800             }
2801             label_set.push(LongStringValueLabels {
2802                 var_name,
2803                 width,
2804                 labels,
2805             })
2806         }
2807         Ok(Record::LongStringValueLabels(LongStringValueLabelRecord(
2808             label_set,
2809         )))
2810     }
2811 }
2812
2813 impl LongStringValueLabelRecord<RawString, RawString> {
2814     fn decode<'a>(
2815         &'a self,
2816         decoder: &Decoder,
2817     ) -> Result<LongStringValueLabelRecord<Identifier, Cow<'a, str>>, Error> {
2818         let mut labels = Vec::with_capacity(self.0.len());
2819         for label in &self.0 {
2820             match label.decode(decoder) {
2821                 Ok(set) => labels.push(set),
2822                 Err(error) => decoder.warn(error),
2823             }
2824         }
2825         Ok(LongStringValueLabelRecord(labels))
2826     }
2827 }