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