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