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