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