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